home *** CD-ROM | disk | FTP | other *** search
/ SGI Hot Mix 17 / Hot Mix 17.iso / HM17_SGI / research / examples / misc / slicer3.pro < prev    next >
Text File  |  1997-07-08  |  257KB  |  6,379 lines

  1. ; $Id: slicer3.pro,v 1.13 1997/04/21 21:03:22 alan Exp $
  2. ;+
  3. ; NAME:
  4. ;       SLICER3
  5. ;
  6. ; PURPOSE:
  7. ;       Widget based application to visualize 3D data.
  8. ;       This program superseeds the "SLICER" program.
  9. ;
  10. ; CATEGORY:
  11. ;       Volume display / rendering.
  12. ;
  13. ; CALLING SEQUENCE:
  14. ;
  15. ;       SLICER3 [, hData3D]
  16. ;
  17. ; INPUTS:
  18. ;       hData3D:    A handle containing the 3D data, or an array of handles
  19. ;                   to multiple 3D arrays.   If multiple arrays are specified,
  20. ;                   they all must have the same X, Y, and Z dimensions.
  21. ;                   This parameter is optional.   The default is to use a 3D
  22. ;                   array created from BYTARR(2,2,2).   While running SLICER3,
  23. ;                   the user may interactively load data via the file menu
  24. ;                   (see example).   If data is loaded in this fashion,
  25. ;                   any data passed to SLICER3 via a handle (or handles) is
  26. ;                   deleted, and the handles become invalid.
  27. ;
  28. ; KEYWORD PARAMETERS:
  29. ;       DETACH:     If set, then the drawing area is placed in a base that is
  30. ;                   detached from the control panel.   The drawing area can
  31. ;                   only be detached if Slicer3 is not run in modal mode.
  32. ;       MODAL:      If set, then Slicer3 will block user interaction with all
  33. ;                   other widgets (and block the command line) until the user
  34. ;                   quits Slicer3.   If Slicer3 is started from some other
  35. ;                   widget-based application, then it is usually advisable
  36. ;                   to run Slicer3 in Modal mode.
  37. ;       GROUP:      This keyword specifies a widget ID of the group leader.
  38. ;                   If the specified widget is destroyed, Slicer3 is also
  39. ;                   destroyed.   If Slicer3 is started from a widget
  40. ;                   application, then GROUP should ALWAYS be specified.
  41. ;                   See example.
  42. ;
  43. ; COMMON BLOCKS:
  44. ;       COMMON colors, r, g, b, cur_red, cur_green, cur_blue
  45. ;                   These common variables are used by the "STRETCH",
  46. ;                   "LOADCT", and "XLOADCT" commands.
  47. ;
  48. ; SIDE EFFECTS:
  49. ;                   Slicer3 modifies the current color table, as well as
  50. ;                   various elements of the plotting system (ie, the "!X",
  51. ;                   "!Y", "!Z", and "!P" system variables).
  52. ;                   If the "MODAL" keyword is set (usually a good idea),
  53. ;                   then SLICER3 will, upon exit, restore these system
  54. ;                   variables (and the color tables) to the values they
  55. ;                   had when SLICER3 was started.
  56. ;                   Slicer3 sets the position for the light source and
  57. ;                   enables back-facing polygons to be drawn (see the
  58. ;                   IDL "SET_SHADING" command).
  59. ;
  60. ;                   Slicer3 overwrites the existing contents of the
  61. ;                   Z-buffer.   Upon exiting Slicer3, the Z-buffer contents
  62. ;                   are the same as what was last displayed by Slicer3.
  63. ;
  64. ;                   On 24-bit displays, Slicer3 sets the device to
  65. ;                   non-decomposed color mode (DEVICE, DECOMPOSED=0).
  66. ;
  67. ;                   Slicer3 breaks the color table into 6 "bands", based upon
  68. ;                   the number of available colors (max_color=!D.N_COLORS
  69. ;                   on 8-bit displays, and max_color=256 on 24-bit displays) :
  70. ;
  71. ;                      Band start index:    Band end index:    Used for:
  72. ;                      -----------------    ---------------    ---------
  73. ;
  74. ;                      0                    nColor-1           X Slices.
  75. ;                      nColor               (2*nColor)-1       Y Slices.
  76. ;                      2*nColor             (3*nColor)-1       Z Slices.
  77. ;                      3*nColor             (4*nColor)-1       Iso-surfaces.
  78. ;                      4*nColor             (5*nColor)-1       Projections.
  79. ;
  80. ;                      Where:
  81. ;                              nColor = (max_color - 9) / 5
  82. ;
  83. ;                      Note that the value of !D.N_Colors can vary from
  84. ;                      machine to machine, and from run to run, depending
  85. ;                      upon available system resources.   Also, !D.N_Colors
  86. ;                      is usually not set by IDL until the first window has
  87. ;                      been created (or realized) in that IDL session.
  88. ;
  89. ;                   Annotation colors are the last "band", and they are
  90. ;                   set up as :
  91. ;
  92. ;                      Color index:     Color:
  93. ;                      -------------    ------
  94. ;
  95. ;                      max_color - 1    White.
  96. ;                      max_color - 2    Yellow.
  97. ;                      max_color - 3    Cyan.
  98. ;                      max_color - 4    Purple.
  99. ;                      max_color - 5    Red.
  100. ;                      max_color - 6    Green.
  101. ;                      max_color - 7    Blue.
  102. ;                      max_color - 8    Black.
  103. ;
  104. ;                   On 24-bit displays, improved performance can often be
  105. ;                   gained by running Slicer3 in 8-bit mode.   This can be
  106. ;                   accomplished (on some platforms) by entering the following
  107. ;                   command at the start of the IDL session (before any
  108. ;                   windows are created):
  109. ;
  110. ;                      Device, Pseudo_Color=8
  111. ;
  112. ;                   See the documentation for additional information.
  113. ;
  114. ; RESTRICTIONS:
  115. ;       The data used by Slicer3 must meet the following conditions:
  116. ;          * The data must have three dimensions.
  117. ;          * The minimum size of the data array must be 2x2x2.
  118. ;          * If multiple volumes are loaded, they all must have the
  119. ;            same dimensions.
  120. ;
  121. ; PROCEDURE:
  122. ;
  123. ;       "File" menu:
  124. ;
  125. ;          "Load":
  126. ;                  Select a file containing a 3D array (or arrays) to load
  127. ;                  into Slicer3.   The file must have been written in a
  128. ;                  certain binary format.   For each data array in the file,
  129. ;                  the following values are present:
  130. ;
  131. ;                     data item                     data type     bytes
  132. ;                     --------------------------    ----------    ------
  133. ;
  134. ;                     Number of dimensions          long          4
  135. ;                     in array.   Note that
  136. ;                     this is always 3 for
  137. ;                     valid Slicer3 data.
  138. ;
  139. ;                     Size of first dimension.      long          4
  140. ;                     Size of second dimension.     long          4
  141. ;                     Size of third dimension.      long          4
  142. ;
  143. ;                        If multiple arrays are present in the file,
  144. ;                        they must all have the same dimensions.
  145. ;
  146. ;                     Data type (1 through 5)       long          4
  147. ;                     (see the IDL "SIZE"
  148. ;                     function for types).
  149. ;
  150. ;                     Total number of elements.     long          4
  151. ;                     (dimX*dimY*dimZ).
  152. ;
  153. ;                        Note that the all of the above values are the
  154. ;                        exact output of the IDL "SIZE" function.
  155. ;
  156. ;                     Number of characters          long          4
  157. ;                     in data name.
  158. ;
  159. ;                        Note that the above value is the output from
  160. ;                        the IDL "STRLEN" function.
  161. ;
  162. ;                     Data name.                    byte          strlen()
  163. ;
  164. ;                     3D data.                      varies        varies
  165. ;
  166. ;                     Note that the 3D data type and number of bytes
  167. ;                     is specified by the "size" information above.
  168. ;
  169. ;                  Any number of 3D datasets can be concatenated into
  170. ;                  a single file of this type (as long as they all have
  171. ;                  the same dimensions).
  172. ;
  173. ;                  (See EXAMPLE, below.)
  174. ;
  175. ;                  NOTE: Files saved by the "Save Subset" operation
  176. ;                  (see below) are suitable for input via the "Load"
  177. ;                  operation.
  178. ;
  179. ;                  Data files that are moved from one platform to
  180. ;                  another may not load as expected, due to differing
  181. ;                  byte order.   See the "BYTEORDER" and "SWAP_ENDIAN"
  182. ;                  IDL commands for details.
  183. ;
  184. ;          "Save / Save Subset":
  185. ;                  Slicer3 must be in "Block" mode for this operation to be
  186. ;                  available.   When selected, a subset of the 3D data
  187. ;                  enclosed in the current block is written to the chosen
  188. ;                  save file.   This subset can then be loaded back into
  189. ;                  Slicer3 at any time.   If multiple 3D arrays are
  190. ;                  currently available in Slicer3, then multiple subsets
  191. ;                  are saved to the file.
  192. ;
  193. ;          "Save / Save Tiff Image":
  194. ;                  When selected, a tiff image of the current Slicer3
  195. ;                  contents is saved to the chosen file.   When running in
  196. ;                  8-bit mode, a "Class P" palette color Tiff file is created.
  197. ;                  In 24-bit mode, a "Class R" (interleaved by image) Tiff
  198. ;                  file is created.
  199. ;
  200. ;          "Quit":
  201. ;                  Exits Slicer3.
  202. ;
  203. ;
  204. ;       "Tools" menu:
  205. ;
  206. ;          "Erase":
  207. ;                  Erases the display window and deletes all the objects
  208. ;                  in the display list.
  209. ;
  210. ;          "Delete / ...":
  211. ;                  As graphical objects are created, they are added to the
  212. ;                  display list.   The "Delete" menu allows the user to
  213. ;                  delete a specific object from the list.   When an object
  214. ;                  is deleted, the screen is redrawn with the remaining
  215. ;                  objects.
  216. ;
  217. ;          "Colors / Reset Colors":
  218. ;                  Selecting this will cause the original color scheme to
  219. ;                  be restored.
  220. ;
  221. ;          "Colors / Differential Shading":
  222. ;                  This allows the user to change the percentage of
  223. ;                  differential shading applied to the X, Y, and Z slices.
  224. ;
  225. ;          "Colors / Slice/Block":
  226. ;                  This allows the user to use the "XLOADCT" operation
  227. ;                  to modify the colors used for slices and blocks.
  228. ;                  In some cases, the new colors will not be visible
  229. ;                  until the user selects "Done" in the XLOADCT tool.
  230. ;
  231. ;          "Colors / Surface":
  232. ;                  This allows the user to use the "XLOADCT" operation
  233. ;                  to modify the colors used for iso-surfaces.
  234. ;
  235. ;          "Colors / Projection":
  236. ;                  This allows the user to use the "XLOADCT" operation
  237. ;                  to modify the colors used for projections.
  238. ;
  239. ;          Note that on some platforms, the selected colors may not
  240. ;          become visible until after the "XLOADCT" tool is exited.
  241. ;
  242. ;          "Options":
  243. ;                  This brings up a panel allowing the user to set:
  244. ;                     The axis visibility.
  245. ;                     The wire-frame cube visibility.
  246. ;                     The display window size
  247. ;                        (the X and Y dimensions are always the same).
  248. ;                  If the user selects "Ok", then the display is redrawn.
  249. ;
  250. ;
  251. ;       "About" menu:
  252. ;
  253. ;          "About Slicer":
  254. ;                  Brings up help information about Slicer3.
  255. ;
  256. ;
  257. ;       "Data:" pull-down menu:
  258. ;                  If multiple datasets are currently available in Slicer3,
  259. ;                  this menu allows the selection of the current data.
  260. ;                  Slices, blocks, iso-surfaces, etc. are created from
  261. ;                  the currently selected data.   If only one dataset
  262. ;                  is currently loaded, then this menu is inactive.
  263. ;
  264. ;
  265. ;       "Mode:" pull-down menu:
  266. ;                  This menu is used to select the current mode of operation.
  267. ;
  268. ;
  269. ;       Main Draw Window:
  270. ;                  Interaction in the main draw window is dependent upon
  271. ;                  the currently selected mode ("Slice", "Block", "Surface",
  272. ;                  etc., see below).   In general, when coordinate input is
  273. ;                  required from the user, it is performed by clicking a
  274. ;                  mouse button on the "surface" of the wire-frame cube that
  275. ;                  surrounds the data.   This 3D location is then used as
  276. ;                  the basis for whatever input is needed.   In most cases,
  277. ;                  the "front" side of the cube is used.   In a few cases,
  278. ;                  the coordinate input is on the "back" side of the cube.
  279. ;
  280. ;
  281. ;       "Slice" mode:
  282. ;                  To display a slice, click and drag the left mouse button
  283. ;                  on the wire-frame cube.   When the button is released, a
  284. ;                  slice through the data will be drawn at that location.
  285. ;
  286. ;          "Draw" mode:
  287. ;                  When in Draw mode, new slices will be merged into
  288. ;                  the current Z-buffer contents.
  289. ;
  290. ;          "Expose" mode:
  291. ;                  When in Expose mode, new slices will be drawn in
  292. ;                  front of everything else.
  293. ;
  294. ;          "Orthogonal" mode:
  295. ;                  When in Orthogonal mode, use the left mouse button
  296. ;                  in the big window to position and draw an orthogonal
  297. ;                  slicing plane.   Clicking the right mouse button in
  298. ;                  the big window (or any mouse button in the small
  299. ;                  window) will toggle the slicing plane orientation.
  300. ;             "X":
  301. ;                  This sets the orthogonal slicing plane orientation
  302. ;                  to be perpendicular to the X axis.
  303. ;             "Y":
  304. ;                  This sets the orthogonal slicing plane orientation
  305. ;                  to be perpendicular to the Y axis.
  306. ;             "Z":
  307. ;                  This sets the orthogonal slicing plane orientation
  308. ;                  to be perpendicular to the Z axis.
  309. ;
  310. ;          "Oblique" mode:
  311. ;                  Clicking any mouse button in the small window will
  312. ;                  reset the oblique slicing plane to its default
  313. ;                  orientation.
  314. ;             "Normal" mode:
  315. ;                  When in this mode, click and drag the left mouse
  316. ;                  button in the big window to set the surface normal
  317. ;                  for the oblique slicing plane.
  318. ;             "Center" mode:
  319. ;                  When in this mode, click and drag the left mouse
  320. ;                  button in the big window to set the center point
  321. ;                  for the surface normal.
  322. ;             "Display":
  323. ;                  Clicking this button will cause an oblique slicing
  324. ;                  plane to be drawn.
  325. ;
  326. ;
  327. ;       "Block" mode:
  328. ;                  When in Block mode, use the left mouse button in the
  329. ;                  big window to set the location for the "purple" corner
  330. ;                  of the block.   Use the right mouse button to locate
  331. ;                  the opposite "blue" corner of the block.
  332. ;
  333. ;                  When in Block mode, the "Save Subset" operation under
  334. ;                  the main "File" menu is available.
  335. ;
  336. ;             "Add" mode:
  337. ;                  When in this mode, the block will be "added" to the
  338. ;                  current Z-buffer contents.
  339. ;
  340. ;             "Subtract" mode:
  341. ;                  When in this mode, the block will be "subtracted"
  342. ;                  from the current Z-buffer contents.   Subtract mode
  343. ;                  is only effective when the block intersects some
  344. ;                  other object in the display (such as an iso-surface).
  345. ;
  346. ;             "Display":
  347. ;                  Clicking this button will cause the block to be drawn.
  348. ;
  349. ;
  350. ;        "Surface" mode:
  351. ;                  In iso-surface is like a contour line on a contour
  352. ;                  map.   On one side of the line, the elevation is higher
  353. ;                  than the contour level, and on the other side of the
  354. ;                  line, the elevation is lower than the contour level.
  355. ;                  An iso-surface, however, is a 3D surface that passes
  356. ;                  through the data such that the data values on one side
  357. ;                  of the surface are higher than the threshold value,
  358. ;                  and on the other side of the surface, the data values
  359. ;                  are lower than the threshold value.
  360. ;
  361. ;                  When in Surface mode, a logarithmic histogram plot
  362. ;                  of the data is displayed in the small draw window.
  363. ;                  Click and drag a mouse button on this plot to set
  364. ;                  the iso-surface threshold value.   This value is
  365. ;                  also shown in the text widget below the plot.
  366. ;                  The threshold value may also be set by typing a
  367. ;                  new value in this text widget.   The histogram
  368. ;                  plot is affected by the current threshold settings.
  369. ;                  (See Threshold mode, below).
  370. ;
  371. ;             "Low":
  372. ;                  Selecting this mode will cause the iso-surface polygon
  373. ;                  facing to face towards the lower data values.
  374. ;                  Usually, this is the mode to use when the iso-surface
  375. ;                  is desired to surround high data values.
  376. ;
  377. ;             "High":
  378. ;                  Selecting this mode will cause the iso-surface polygon
  379. ;                  facing to face towards the higher data values.
  380. ;                  Usually, this is the mode to use when the iso-surface
  381. ;                  is desired to surround low data values.
  382. ;
  383. ;             "Shading" pull-down menu:
  384. ;                  Iso-surfaces are normally rendered with light-source
  385. ;                  shading.   If multiple datasets are currently loaded,
  386. ;                  then this menu allows the selection of a different
  387. ;                  3D array for the source of the iso-surface shading
  388. ;                  values.   If only one dataset is currently loaded,
  389. ;                  then this menu is inactive.
  390. ;
  391. ;             "Display":
  392. ;                  Clicking this button will cause the iso-surface to
  393. ;                  be created and drawn.   Iso-surfaces often consist
  394. ;                  of tens of thousands of polygons, and can sometimes
  395. ;                  take considerable time to create and render.
  396. ;
  397. ;
  398. ;        "Projection" mode:
  399. ;                  A "voxel" projection of a 3D array is the projection
  400. ;                  of the data values within that array onto a viewing
  401. ;                  plane.   This is similar to taking an X-ray image of
  402. ;                  a 3D object.
  403. ;
  404. ;             "Max" mode:
  405. ;                  Select this mode for a Maximum intensity projection.
  406. ;
  407. ;             "Avg" mode:
  408. ;                  Select this mode for an Average intensity projection.
  409. ;
  410. ;             "Low" mode:
  411. ;                  Select this mode for a Low resolution projection.
  412. ;
  413. ;             "Med" mode:
  414. ;                  Select this mode for a Medium resolution projection.
  415. ;
  416. ;             "High" mode:
  417. ;                  Select this mode for a High resolution projection.
  418. ;
  419. ;             "Depth Queue %":
  420. ;                  Use the slider to set the depth queue percent.
  421. ;                  A value of 50, for example, indicates that the
  422. ;                  farthest part of the projection will be 50 % as
  423. ;                  bright as the closest part of the projection.
  424. ;
  425. ;             "Display":
  426. ;                  Clicking this button will cause the projection to
  427. ;                  be calculated and drawn.   Projections can sometimes
  428. ;                  take considerable time to display.   Higher resolution
  429. ;                  projections take more computation time.
  430. ;
  431. ;
  432. ;        "Threshold" mode:
  433. ;                  When in Threshold mode, a logarithmic histogram plot
  434. ;                  of the data is displayed in the small draw window.
  435. ;                  Click and drag the left mouse button on this plot to
  436. ;                  set the minimum and maximum threshold values.
  437. ;                  To expand a narrow range of data values into the
  438. ;                  full range of available colors, set the threshold
  439. ;                  range before displaying slices, blocks, or projections.
  440. ;                  The threshold settings also affect the histogram
  441. ;                  plot in "Surface" mode.   The minimum and maximum
  442. ;                  threshold values are also shown in the text widgets
  443. ;                  below the histogram plot.
  444. ;
  445. ;                  Click and drag the right mouse button on the histogram
  446. ;                  plot to set the transparency threshold.
  447. ;                  Portions of any slice, block, or projection that are
  448. ;                  less than the transparency value are not drawn (clear).
  449. ;                  Iso-surfaces are not affected by the transparency
  450. ;                  threshold.   The transparency threshold value is also
  451. ;                  shown in a text widget below the histogram plot.
  452. ;
  453. ;           "Min":
  454. ;                  In this text widget, a minimum threshold value can
  455. ;                  be entered.
  456. ;
  457. ;           "Max":
  458. ;                  In this text widget, a maximum threshold value can
  459. ;                  be entered.
  460. ;
  461. ;           "Transp.":
  462. ;                  In this text widget, a transparency threshold value
  463. ;                  can be entered.
  464. ;
  465. ;
  466. ;        "Profile" mode:
  467. ;                  In Profile mode, a plot is displayed showing the
  468. ;                  data values along a line.   This line is also shown
  469. ;                  superimposed on the data in the main draw window.
  470. ;                  The bottom of the plot corresponds to the "purple"
  471. ;                  end of the line, and the top of the plot corresponds
  472. ;                  to the "blue" end of the line.
  473. ;
  474. ;           "Orthogonal" mode:
  475. ;                  Click and drag the left mouse button to position the
  476. ;                  profile line, based upon a point on the "front"
  477. ;                  faces of the wire-frame cube.   Click and drag the
  478. ;                  right mouse button to position the profile line,
  479. ;                  based upon a point on the "back" faces of the
  480. ;                  wire-frame cube.   As the profile line is moved,
  481. ;                  The profile plot is dynamically updated.
  482. ;
  483. ;           "Oblique" mode:
  484. ;                  Click and drag the left mouse button to position the
  485. ;                  "purple" end of the profile line on one of the "front"
  486. ;                  faces of the wire-frame cube.   Click and drag the
  487. ;                  right mouse button to position the "blue" end of the
  488. ;                  profile line on one of the "back" faces of the
  489. ;                  wire-frame cube.   As the profile line is moved,
  490. ;                  The profile plot is dynamically updated.
  491. ;
  492. ;
  493. ;        "Probe" mode:
  494. ;                  In Probe mode, click and drag a mouse button over
  495. ;                  an object in the main draw window.   The actual
  496. ;                  X-Y-Z location within the data volume is displayed
  497. ;                  in the three text widgets.   Also, the data value
  498. ;                  at that 3D location is displayed in the status
  499. ;                  window, above the main draw window.   If the cursor
  500. ;                  is inside the wire-frame cube, but not on any object,
  501. ;                  then the status window displays "No data value", and
  502. ;                  the three text widgets are empty.  If the cursor is
  503. ;                  outside the wire-frame cube, then the status window
  504. ;                  and text widgets are empty.
  505. ;
  506. ;           "X":
  507. ;                  Use this text widget to enter the X coordinate for
  508. ;                  the probe.
  509. ;
  510. ;           "Y":
  511. ;                  Use this text widget to enter the Y coordinate for
  512. ;                  the probe.
  513. ;
  514. ;           "Z":
  515. ;                  Use this text widget to enter the Z coordinate for
  516. ;                  the probe.
  517. ;
  518. ;
  519. ;        "View" mode:
  520. ;                  In view mode, a small window shows the orientation
  521. ;                  of the data cube in the current view.   As view
  522. ;                  parameters are changed, this window is dynamically
  523. ;                  updated.   The main draw window is then updated
  524. ;                  when the user clicks on "Display", or exits View
  525. ;                  mode.
  526. ;
  527. ;        "Display":
  528. ;                  Clicking on this button will cause the objects in
  529. ;                  the main view window to be drawn in the new view.
  530. ;                  If any view parameters have been changed since
  531. ;                  the last time the main view was updated, the main
  532. ;                  view will be automatically redrawn when the user
  533. ;                  exits View mode.
  534. ;
  535. ;        1st Rotation:
  536. ;                  Use this slider to set the angle of the first view
  537. ;                  rotation (in degrees).   The droplist widget adjacent
  538. ;                  to the slider indicates which axis this rotation is
  539. ;                  about.
  540. ;
  541. ;        2nd Rotation:
  542. ;                  Use this slider to set the angle of the second view
  543. ;                  rotation (in degrees).   The droplist widget adjacent
  544. ;                  to the slider indicates which axis this rotation is
  545. ;                  about.
  546. ;
  547. ;        "Zoom %":
  548. ;                  Use this slider to set the zoom factor percent.
  549. ;                  Depending upon the view rotations, Slicer3 may
  550. ;                  override this setting to ensure that all eight
  551. ;                  corners of the data cube are within the window.
  552. ;
  553. ;        "Z %":
  554. ;                  Use this slider to set a scale factor for the Z
  555. ;                  axis (to compensate for the data's aspect ratio).
  556. ;
  557. ;
  558. ; EXAMPLE:
  559. ;       Example 1:
  560. ;       ----------
  561. ;       Create a data save file suitable for dynamic loading into
  562. ;       Slicer3.
  563. ;
  564. ;
  565. ;               ; Store some 3D data in a variable called "data_1".
  566. ;               data_1 = INDGEN(20,30,40)
  567. ;
  568. ;               ; Store some 3D data in a variable called "data_2".
  569. ;               data_2 = FINDGEN(20,30,40)
  570. ;
  571. ;               ; Define the names for the datasets (their names will
  572. ;               ; appear in the "Data:" pull-down menu in Slicer3.
  573. ;
  574. ;               data_1_name = 'Test Data 1'
  575. ;               data_2_name = 'Data 2'
  576. ;
  577. ;               ; Select a data file name.
  578. ;               dataFile = PICKFILE()
  579. ;
  580. ;               ; Write the file.
  581. ;
  582. ;               GET_LUN, lun
  583. ;               OPENW, lun, dataFile
  584. ;
  585. ;               WRITEU, lun, SIZE(data_1)
  586. ;               WRITEU, lun, STRLEN(data_1_name)
  587. ;               WRITEU, lun, BYTE(data_1_name)
  588. ;               WRITEU, lun, data_1
  589. ;
  590. ;               WRITEU, lun, SIZE(data_2)
  591. ;               WRITEU, lun, STRLEN(data_2_name)
  592. ;               WRITEU, lun, BYTE(data_2_name)
  593. ;               WRITEU, lun, data_2
  594. ;
  595. ;               CLOSE, lun
  596. ;               FREE_LUN, lun
  597. ;
  598. ;
  599. ;       Example 2:
  600. ;       ----------
  601. ;       Run Slicer3 with data passed to it at startup.
  602. ;
  603. ;               ; Create some 3D data.
  604. ;               data = INDGEN(20,30,40)
  605. ;
  606. ;               ; Create a handle to the data, and use the "/NO_COPY"
  607. ;               ; keyword to save memory.
  608. ;               h_data = HANDLE_CREATE(VALUE=data, /NO_COPY)
  609. ;
  610. ;               ; Start up Slicer3.
  611. ;               SLICER3, h_data, /MODAL
  612. ;
  613. ;               ; If the user did not interactively load any data into
  614. ;               ; Slicer3 (via the "File/Load" menu), then the original
  615. ;               ; handle to the data still exists (and the original data
  616. ;               ; will still reside in memory).   To free it, use:
  617. ;
  618. ;               if HANDLE_INFO(h_data, /VALID_ID) then HANDLE_FREE, h_data
  619. ;
  620. ;               ; If the handle is no longer valid, then that indicates
  621. ;               ; that the user interactively loaded data into Slicer3.
  622. ;               ; Any data that is loaded interactively is automatically
  623. ;               ; deleted when the user exits Slicer3.
  624. ;
  625. ;               ; Note that the last contents of the main view window in
  626. ;               ; Slicer3 still resides in the Z-buffer.   To access this
  627. ;               ; image after exiting Slicer3, perform the following actions:
  628. ;
  629. ;               current_device = !D.Name
  630. ;               SET_PLOT, 'Z'
  631. ;               image_buffer = TVRD()
  632. ;               depth_buffer = TVRD(CHANNEL=1, /WORDS)
  633. ;               SET_PLOT, current_device
  634. ;               TV, image_buffer
  635. ;
  636. ;               ; Note that the image contained in "image_buffer" will look
  637. ;               ; "correct" only if the colors loaded by Slicer3 have not
  638. ;               ; been changed since the user exited Slicer3.
  639. ;
  640. ;
  641. ; MODIFICATION HISTORY:
  642. ;       Daniel Carr - RSI, Fri Nov 22 15:43:36 MST 1996
  643. ;       Daniel Carr - RSI, Fri Jan 10 12:08:01 MST 1997
  644. ;          Fixed bugs and added muti-dataset capability.
  645. ;
  646. ;
  647. ;-
  648.  
  649. ;******************************************************************************
  650. ; Procedure to reset IDL system variables to their initial start-up states.
  651. pro Viz3D_Reset
  652.  
  653.    !Order = 0
  654.  
  655.    T3d, /Reset
  656.    !P.T3d = 0
  657.    !P.Position = [0.0, 0.0, 0.0, 0.0]
  658.    !P.Clip = [0L, 0L, (!D.X_Size-1L), (!D.Y_Size-1L), 0L, 0L]
  659.    !P.Region = [0.0, 0.0, 0.0, 0.0]
  660.    !P.Background = 0L
  661.    !P.Charsize = 0.0
  662.    !P.Charthick = 0.0
  663.    !P.Color = 255
  664.    !P.Font = (-1L)
  665.    !P.Linestyle = 0L
  666.    !P.Multi = [0L, 0L, 0L, 0L, 0L]
  667.    !P.Noclip = 0L
  668.    !P.Noerase = 0L
  669.    !P.Nsum = 0L
  670.    !P.Psym = 0L
  671.    !P.Subtitle = ''
  672.    !P.Symsize = 0.0
  673.    !P.Thick = 0.0
  674.    !P.Title = ''
  675.    !P.Ticklen = 0.02
  676.    !P.Channel = 0
  677.  
  678.    !X.S = [0.0, 0.0]
  679.    !X.Style = 0L
  680.    !X.Range = [0.0, 0.0]
  681.    !X.Margin = [10.0, 3.0]
  682.    !X.Type = 0L
  683.    !X.Ticks = 0L
  684.    !X.Ticklen = 0.0
  685.    !X.Thick = 0.0
  686.    !X.Crange = [0.0, 0.0]
  687.    !X.Omargin = [0.0, 0.0]
  688.    !X.Window = [0.0, 0.0]
  689.    !X.Region = [0.0, 0.0]
  690.    !X.Charsize = 0.0
  691.    !X.Minor = 0L
  692.    !X.Tickv = Replicate(0.0, 30)
  693.    !X.Tickname = Replicate('', 30)
  694.    !X.Gridstyle = 0L
  695.    !X.Tickformat = ''
  696.    !X.Title = ''
  697.  
  698.    !Y.S = [0.0, 0.0]
  699.    !Y.Style = 0L
  700.    !Y.Range = [0.0, 0.0]
  701.    !Y.Margin = [4.0, 2.0]
  702.    !Y.Type = 0L
  703.    !Y.Ticks = 0L
  704.    !Y.Ticklen = 0.0
  705.    !Y.Thick = 0.0
  706.    !Y.Crange = [0.0, 0.0]
  707.    !Y.Omargin = [0.0, 0.0]
  708.    !Y.Window = [0.0, 0.0]
  709.    !Y.Region = [0.0, 0.0]
  710.    !Y.Charsize = 0.0
  711.    !Y.Minor = 0L
  712.    !Y.Tickv = Replicate(0.0, 30)
  713.    !Y.Tickname = Replicate('', 30)
  714.    !Y.Gridstyle = 0L
  715.    !Y.Tickformat = ''
  716.    !Y.Title = ''
  717.  
  718.    !Z.S = [0.0, 0.0]
  719.    !Z.Style = 0L
  720.    !Z.Range = [0.0, 0.0]
  721.    !Z.Margin = [0.0, 0.0]
  722.    !Z.Type = 0L
  723.    !Z.Ticks = 0L
  724.    !Z.Ticklen = 0.0
  725.    !Z.Thick = 0.0
  726.    !Z.Crange = [0.0, 0.0]
  727.    !Z.Omargin = [0.0, 0.0]
  728.    !Z.Window = [0.0, 0.0]
  729.    !Z.Region = [0.0, 0.0]
  730.    !Z.Charsize = 0.0
  731.    !Z.Minor = 0L
  732.    !Z.Tickv = Replicate(0.0, 30)
  733.    !Z.Tickname = Replicate('', 30)
  734.    !Z.Gridstyle = 0L
  735.    !Z.Tickformat = ''
  736.    !Z.Title = ''
  737.  
  738. end
  739. ;******************************************************************************
  740.  
  741.  
  742. ;******************************************************************************
  743. ; Procedure to set the differential shading.
  744. pro Viz3D_DiffColor, sViz3DColors
  745.    ; IDL colors common block (used by "LOADCT" and "STRETCH").
  746.    common colors, r, g, b, cur_red, cur_green, cur_blue
  747.  
  748.    fdiffShade = Float(sViz3DColors.diffShade) / 100.0
  749.  
  750.    cR1 = (sViz3DColors.rSlice * (1.0 - fdiffshade))
  751.    cG1 = (sViz3DColors.gSlice * (1.0 - fdiffshade))
  752.    cB1 = (sViz3DColors.bSlice * (1.0 - fdiffshade))
  753.    TVLCT, cR1, cG1, cB1, 0
  754.  
  755.    cR1 = (sViz3DColors.rSlice * (1.0 - fdiffshade)) + $
  756.          (127.0 * fdiffshade)
  757.    cG1 = (sViz3DColors.gSlice * (1.0 - fdiffshade)) + $
  758.          (127.0 * fdiffshade)
  759.    cB1 = (sViz3DColors.bSlice * (1.0 - fdiffshade)) + $
  760.          (127.0 * fdiffshade)
  761.    TVLCT, cR1, cG1, cB1, sViz3DColors.nColor
  762.  
  763.    cR1 = (sViz3DColors.rSlice * (1.0 - fdiffshade)) + $
  764.          (255.0 * fdiffshade)
  765.    cG1 = (sViz3DColors.gSlice * (1.0 - fdiffshade)) + $
  766.          (255.0 * fdiffshade)
  767.    cB1 = (sViz3DColors.bSlice * (1.0 - fdiffshade)) + $
  768.          (255.0 * fdiffshade)
  769.    TVLCT, cR1, cG1, cB1, (2 * sViz3DColors.nColor)
  770.  
  771.    TVLCT, cur_red, cur_green, cur_blue, /GET
  772.    sViz3DColors.cR = cur_red
  773.    sViz3DColors.cG = cur_green
  774.    sViz3DColors.cB = cur_blue
  775.  
  776.    if (sViz3DColors.displayBits eq 24) then LOADCT, 0
  777.  
  778. end
  779. ;******************************************************************************
  780.  
  781.  
  782. ;******************************************************************************
  783. ; Function to load a color table and set the annotation colors.
  784. ; Returns the color state.
  785. function Viz3D_LoadColor, CTAB=cTab, DIFFSHADE=diffShade
  786.    ; IDL colors common block (used by "LOADCT" and "STRETCH").
  787.    common colors, r, g, b, cur_red, cur_green, cur_blue
  788.  
  789.    ;Annotation color numbers :
  790.    ; 0 - Black.
  791.    ; 1 - Blue.
  792.    ; 2 - Green.
  793.    ; 3 - Red.
  794.    ; 4 - Purple.
  795.    ; 5 - Cyan.
  796.    ; 6 - Yellow.
  797.    ; 7 - White.
  798.  
  799.    nColor = ((!D.N_Colors < 256) - 9) / 5
  800.    white  = LONG([255, 255, 255])
  801.    yellow = LONG([255, 255,   0])
  802.    cyan   = LONG([  0, 255, 255])
  803.    purple = LONG([191,   0, 191])
  804.    red    = LONG([255,   0,   0])
  805.    green  = LONG([  0, 255,   0])
  806.    blue   = LONG([ 63,  63, 255])
  807.    black  = LONG([  0,   0,   0])
  808.  
  809.    if (N_ELEMENTS(cTab) le 3L) then cTab = [3,1,8]
  810.  
  811.    LOADCT, cTab(0)
  812.    STRETCH, 0, (nColor-1)
  813.    rSlice = cur_red(0:nColor-1)
  814.    gSlice = cur_green(0:nColor-1)
  815.    bSlice = cur_blue(0:nColor-1)
  816.  
  817.    LOADCT, cTab(1)
  818.    STRETCH, 0, (nColor-1)
  819.    rSurfc = cur_red(0:nColor-1)
  820.    gSurfc = cur_green(0:nColor-1)
  821.    bSurfc = cur_blue(0:nColor-1)
  822.  
  823.    LOADCT, cTab(2)
  824.    STRETCH, 0, (nColor-1)
  825.    rPrjct = cur_red(0:nColor-1)
  826.    gPrjct = cur_green(0:nColor-1)
  827.    bPrjct = cur_blue(0:nColor-1)
  828.  
  829.    if (!D.N_Colors gt 256) then displayBits = 24 else displayBits = 8
  830.  
  831.    cWhite24 = (white(2) * 256L^2L) + (white(1) * 256L) + white(0)
  832.    cYellow24 = (yellow(2) * 256L^2L) + (yellow(1) * 256L) + yellow(0)
  833.    cCyan24 = (cyan(2) * 256L^2L) + (cyan(1) * 256L) + cyan(0)
  834.    cPurple24 = (purple(2) * 256L^2L) + (purple(1) * 256L) + purple(0)
  835.    cRed24 = (red(2) * 256L^2L) + (red(1) * 256L) + red(0)
  836.    cGreen24 = (green(2) * 256L^2L) + (green(1) * 256L) + green(0)
  837.    cBlue24 = (blue(2) * 256L^2L) + (blue(1) * 256L) + blue(0)
  838.    cBlack24 = (black(2) * 256L^2L) + (black(1) * 256L) + black(0)
  839.  
  840.    nCol = !D.N_Colors < 256
  841.  
  842.    cWhite = nCol - 1
  843.    cYellow = nCol - 2
  844.    cCyan = nCol - 3
  845.    cPurple = nCol - 4
  846.    cRed = nCol - 5
  847.    cGreen = nCol - 6
  848.    cBlue = nCol - 7
  849.    cBlack = nCol - 8
  850.  
  851.    colors8 = [cBlack,cBlue,cGreen,cRed,cPurple,cCyan,cYellow,cWhite]
  852.    colors24 = [cBlack24,cBlue24,cGreen24,cRed24,$
  853.                cPurple24,cCyan24,cYellow24,cWhite24]
  854.  
  855.    TVLCT, rSurfc, gSurfc, bSurfc, (3 * nColor)
  856.    TVLCT, rPrjct, gPrjct, bPrjct, (4 * nColor)
  857.    TVLCT, REFORM(white, 1, 3), cWhite
  858.    TVLCT, REFORM(yellow, 1, 3), cYellow
  859.    TVLCT, REFORM(cyan, 1, 3), cCyan
  860.    TVLCT, REFORM(purple, 1, 3), cPurple
  861.    TVLCT, REFORM(red, 1, 3), cRed
  862.    TVLCT, REFORM(green, 1, 3), cGreen
  863.    TVLCT, REFORM(blue, 1, 3), cBlue
  864.    TVLCT, REFORM(black, 1, 3), cBlack
  865.  
  866.    sViz3DColors = {SViz3DColors, nColor:nColor, diffShade:diffShade, $
  867.                    colors8:colors8, colors24:colors24, $
  868.                    displayBits:displayBits, $
  869.                    cR:cur_red, cG:cur_green, cB:cur_blue, $
  870.                    rSlice:rSlice, gSlice:gSlice, bSlice:bSlice}
  871.  
  872.    Viz3D_DiffColor, sViz3DColors
  873.  
  874.    TVLCT, cur_red, cur_green, cur_blue, /Get
  875.  
  876.    if (displayBits eq 24) then LOADCT, 0
  877.  
  878.    return, sViz3DColors
  879.  
  880. end
  881. ;******************************************************************************
  882.  
  883.  
  884. ;******************************************************************************
  885. ; Function to translate an annotation color
  886. ; number to an actual color table index.
  887. function Viz3D_TransColor, sMainState, cIndex
  888.  
  889.    if ((sMainState.sColorState.displayBits eq 24) and (!D.Name NE 'Z')) then $
  890.       return, sMainState.sColorState.colors24(cIndex) $
  891.    else $
  892.       return, sMainState.sColorState.colors8(cIndex)
  893.  
  894. end
  895. ;******************************************************************************
  896.  
  897.  
  898. ;******************************************************************************
  899. ; Function to set up the 3D view.
  900. ; Returns the view state.
  901. function Viz3D_View, viewWin, $
  902.                      XMAX=xMax, YMAX=yMax, ZMAX=zMax, $
  903.                      ANG1=ang1, ANG2=ang2, ANG3=ang3, $
  904.                      DIR1=dir1, DIR2=dir2, DIR3=dir3, $
  905.                      ZOOM=zoomFac, ZSCALE=zScale, PERSP=pDist
  906.  
  907.    if (N_ELEMENTS(xMax) le 0L) then xMax = 1.0
  908.    if (N_ELEMENTS(yMax) le 0L) then yMax = 1.0
  909.    if (N_ELEMENTS(zMax) le 0L) then zMax = 1.0
  910.  
  911.    if (N_ELEMENTS(ang1) le 0L) then ang1 = 0.0
  912.    if (N_ELEMENTS(ang2) le 0L) then ang2 = 0.0
  913.    if (N_ELEMENTS(ang3) le 0L) then ang3 = 0.0
  914.    if (N_ELEMENTS(dir1) le 0L) then dir1 = 'Z'
  915.    if (N_ELEMENTS(dir2) le 0L) then dir2 = 'Y'
  916.    if (N_ELEMENTS(dir3) le 0L) then dir3 = 'X'
  917.    if (N_ELEMENTS(zoomFac) le 0L) then zoomFac = 1.0
  918.    if (N_ELEMENTS(zScale) le 0L) then zScale = 1.0
  919.    if (N_ELEMENTS(pDist) le 0L) then pDist = 0.0
  920.  
  921.    s_ang1 = Sin(ang1*!Dtor)
  922.    c_ang1 = Cos(ang1*!Dtor)
  923.    s_ang2 = Sin(ang2*!Dtor)
  924.    c_ang2 = Cos(ang2*!Dtor)
  925.    s_ang3 = Sin(ang3*!Dtor)
  926.    c_ang3 = Cos(ang3*!Dtor)
  927.  
  928.    ident4 = FLTARR(4, 4)
  929.    ident4([0,5,10,15]) = 1.0
  930.  
  931.    vTrans = ident4
  932.  
  933.    ; First translation.
  934.    m4X4 = ident4
  935.    m4X4([3,7,11]) = (-0.5)
  936.    vTrans = TEMPORARY(vTrans) # m4X4
  937.  
  938.    ; Scale for aspect ratio.
  939.    xRange = FLOAT(xMax)
  940.    yRange = FLOAT(yMax)
  941.    zRange = FLOAT(zMax) * (zScale > 1.0)
  942.    maxRange = xRange > yRange > zRange
  943.    xyzFac = [xRange, yRange, zRange] / maxRange
  944.    m4X4 = ident4
  945.    m4X4(0,0) = xyzFac(0)
  946.    m4X4(1,1) = xyzFac(1)
  947.    m4X4(2,2) = xyzFac(2)
  948.    vTrans = TEMPORARY(vTrans) # m4X4
  949.  
  950.    ; Z scale.
  951.    if (zScale lt 1.0) then begin
  952.       m4X4 = ident4
  953.       m4X4(2,2) = zScale
  954.       vTrans = TEMPORARY(vTrans) # m4X4
  955.    endif
  956.    if (zScale gt 1.0) then begin
  957.       zFac = 1.0 / zScale
  958.       m4X4 = ident4
  959.       m4X4(0,0) = zFac
  960.       m4X4(1,1) = zFac
  961.       vTrans = TEMPORARY(vTrans) # m4X4
  962.    endif
  963.  
  964.    ; First rotation.
  965.    m4x4 = ident4
  966.    case dir1 of
  967.       'X': begin ; Rotate about x.
  968.          m4x4(1,1) = c_ang1
  969.          m4x4(1,2) = s_ang1
  970.          m4x4(2,1) = (-s_ang1)
  971.          m4x4(2,2) = c_ang1
  972.       end
  973.       'Y': begin ; Rotate about y.
  974.          m4x4(0,0) = c_ang1
  975.          m4x4(0,2) = (-s_ang1)
  976.          m4x4(2,0) = s_ang1
  977.            m4x4(2,2) = c_ang1
  978.       end
  979.       'Z': begin ; Rotate about z.
  980.          m4x4(0,0) = c_ang1
  981.          m4x4(0,1) = s_ang1
  982.          m4x4(1,0) = (-s_ang1)
  983.          m4x4(1,1) = c_ang1
  984.       end
  985.    endcase
  986.    vTrans = TEMPORARY(vTrans) # m4X4
  987.  
  988.    ; Second rotation.
  989.    m4x4 = ident4
  990.    case dir2 of
  991.       'X': begin ; Rotate about x.
  992.          m4x4(1,1) = c_ang2
  993.          m4x4(1,2) = s_ang2
  994.          m4x4(2,1) = (-s_ang2)
  995.          m4x4(2,2) = c_ang2
  996.       end
  997.       'Y': begin ; Rotate about y.
  998.          m4x4(0,0) = c_ang2
  999.          m4x4(0,2) = (-s_ang2)
  1000.          m4x4(2,0) = s_ang2
  1001.          m4x4(2,2) = c_ang2
  1002.       end
  1003.       'Z': begin ; Rotate about z.
  1004.          m4x4(0,0) = c_ang2
  1005.          m4x4(0,1) = s_ang2
  1006.          m4x4(1,0) = (-s_ang2)
  1007.          m4x4(1,1) = c_ang2
  1008.       end
  1009.    endcase
  1010.    vTrans = TEMPORARY(vTrans) # m4X4
  1011.  
  1012.    ; Third rotation.
  1013.    m4x4 = ident4
  1014.    case dir3 of
  1015.       'X': begin ; Rotate about x.
  1016.          m4x4(1,1) = c_ang3
  1017.          m4x4(1,2) = s_ang3
  1018.          m4x4(2,1) = (-s_ang3)
  1019.          m4x4(2,2) = c_ang3
  1020.       end
  1021.       'Y': begin ; Rotate about y.
  1022.          m4x4(0,0) = c_ang3
  1023.          m4x4(0,2) = (-s_ang3)
  1024.          m4x4(2,0) = s_ang3
  1025.          m4x4(2,2) = c_ang3
  1026.       end
  1027.       'Z': begin ; Rotate about z.
  1028.          m4x4(0,0) = c_ang3
  1029.          m4x4(0,1) = s_ang3
  1030.          m4x4(1,0) = (-s_ang3)
  1031.          m4x4(1,1) = c_ang3
  1032.       end
  1033.    endcase
  1034.    vTrans = TEMPORARY(vTrans) # m4X4
  1035.  
  1036.    ; Perspective.
  1037.    if (pDist gt 0.0) then begin
  1038.       pD2 = SQRT(pDist)
  1039.       m4X4 = ident4
  1040.       m4X4(2,3) = (-1.0 / pD2)
  1041.       vTrans = TEMPORARY(vTrans) # m4X4
  1042.    endif
  1043.  
  1044.    ; Zoom.
  1045.    m4X4 = ident4
  1046.    m4X4(0,0) = zoomFac
  1047.    m4X4(1,1) = zoomFac
  1048.    m4X4(2,2) = zoomFac
  1049.    vTrans = TEMPORARY(vTrans) # m4X4
  1050.  
  1051.    ; Zoom down so that all 8 corners of the
  1052.    ; unit cube are within the view.
  1053.    corners = Fltarr(3,8)
  1054.    corners(*,0) = [0,0,0]
  1055.    corners(*,1) = [1,0,0]
  1056.    corners(*,2) = [1,1,0]
  1057.    corners(*,3) = [0,1,0]
  1058.    corners(*,4) = [0,0,1]
  1059.    corners(*,5) = [1,0,1]
  1060.    corners(*,6) = [1,1,1]
  1061.    corners(*,7) = [0,1,1]
  1062.    corners = VERT_T3D(corners, Matrix=vTrans, /NO_COPY)
  1063.    sFac = (1.0 / (1.0 + (2.0 * (MAX(ABS(corners(0:1,*))) - 0.5)))) < 1.0
  1064.    if (sFac lt 1.0) then begin
  1065.       m4X4 = ident4
  1066.       m4X4(0,0) = sFac
  1067.       m4X4(1,1) = sFac
  1068.       m4X4(2,2) = sFac
  1069.       vTrans = TEMPORARY(vTrans) # m4X4
  1070.    endif
  1071.  
  1072.    m4X4 = ident4
  1073.    m4X4(2,2) = (0.1)
  1074.    vTrans = TEMPORARY(vTrans) # m4X4
  1075.  
  1076.    ; Last translation.
  1077.    m4X4 = ident4
  1078.    m4X4([3,7,11]) = (0.5)
  1079.    vTrans = TEMPORARY(vTrans) # m4X4
  1080.  
  1081.    ; System variables.
  1082.    !P.T = vTrans
  1083.    !X.S = [0.0, (1.0 / xRange)]
  1084.    !Y.S = [0.0, (1.0 / yRange)]
  1085.    !Z.S = [0.0, (1.0 / FLOAT(zMax))]
  1086.  
  1087.    sViz3DView = {SViz3DView, viewWin:viewWin, $
  1088.                  xMax:xMax, yMax:yMax, zMax:zMax, $
  1089.                  ang1:ang1, ang2:ang2, ang3:ang3, $
  1090.                  dir1:dir1, dir2:dir2, dir3:dir3, $
  1091.                  zoomFac:zoomFac, zScale:zScale, pDist:pDist, $
  1092.                  vTrans:vTrans, invTrans:INVERT(vTrans)}
  1093.  
  1094.    return, sViz3DView
  1095.  
  1096. end
  1097. ;******************************************************************************
  1098.  
  1099.  
  1100. ;******************************************************************************
  1101. ; Procedure to save the depth buffer information for the cube's outer surface.
  1102. ; This depth info is used to find the XYZ data coordinate on the surface of
  1103. ; the cube, given a user selected screen XY coordinate.
  1104. pro Viz3D_FillDepth, sMainState
  1105.  
  1106.    SET_PLOT, 'Z'
  1107.    image = TVRD()
  1108.    depth = TVRD(CHANNEL=1, /WORDS)
  1109.  
  1110.    ; Front faces.
  1111.    ERASE, 0
  1112.    norm = [[0.0,0.0,0.0], [0.0,0.0,(-1.0)]]
  1113.    norm = VERT_T3D(norm, /NO_COPY)
  1114.    if ((norm(2,1)-norm(2,0)) gt 0.0) then $
  1115.       POLYFILL, [0,1,1,0], [0,0,1,1], [0,0,0,0], /NORMAL, /T3D, COLOR=1
  1116.  
  1117.    norm = [[0.0,0.0,0.0], [0.0,(-1.0),0.0]]
  1118.    norm = VERT_T3D(norm, /NO_COPY)
  1119.    if ((norm(2,1)-norm(2,0)) gt 0.0) then $
  1120.       POLYFILL, [0,1,1,0], [0,0,0,0], [0,0,1,1], /NORMAL, /T3D, COLOR=2
  1121.  
  1122.    norm = [[0.0,0.0,0.0], [(-1.0),0.0,0.0]]
  1123.    norm = VERT_T3D(norm, /NO_COPY)
  1124.    if ((norm(2,1)-norm(2,0)) gt 0.0) then $
  1125.       POLYFILL, [0,0,0,0], [0,1,1,0], [0,0,1,1], /NORMAL, /T3D, COLOR=3
  1126.  
  1127.    norm = [[1.0,1.0,1.0], [1.0,1.0,2.0]]
  1128.    norm = VERT_T3D(norm, /NO_COPY)
  1129.    if ((norm(2,1)-norm(2,0)) gt 0.0) then $
  1130.       POLYFILL, [0,1,1,0], [0,0,1,1], [1,1,1,1], /NORMAL, /T3D, COLOR=1
  1131.  
  1132.    norm = [[1.0,1.0,1.0], [1.0,2.0,1.0]]
  1133.    norm = VERT_T3D(norm, /NO_COPY)
  1134.    if ((norm(2,1)-norm(2,0)) gt 0.0) then $
  1135.       POLYFILL, [0,1,1,0], [1,1,1,1], [0,0,1,1], /NORMAL, /T3D, COLOR=2
  1136.  
  1137.    norm = [[1.0,1.0,1.0], [2.0,1.0,1.0]]
  1138.    norm = VERT_T3D(norm, /NO_COPY)
  1139.    if ((norm(2,1)-norm(2,0)) gt 0.0) then $
  1140.       POLYFILL, [1,1,1,1], [0,1,1,0], [0,0,1,1], /NORMAL, /T3D, COLOR=3
  1141.  
  1142.    HANDLE_VALUE, sMainState.hFrontImage, TVRD(), /SET
  1143.    HANDLE_VALUE, sMainState.hFrontDepth, TVRD(CHANNEL=1, /WORDS), /SET
  1144.  
  1145.    ; Back faces.
  1146.    ERASE, 0
  1147.  
  1148.    norm = [[0.0,0.0,0.0], [0.0,0.0,(-1.0)]]
  1149.    norm = VERT_T3D(norm, /NO_COPY)
  1150.    if ((norm(2,1)-norm(2,0)) lt 0.0) then $
  1151.       POLYFILL, [0,1,1,0], [0,0,1,1], [0,0,0,0], /NORMAL, /T3D, COLOR=1
  1152.  
  1153.    norm = [[0.0,0.0,0.0], [0.0,(-1.0),0.0]]
  1154.    norm = VERT_T3D(norm, /NO_COPY)
  1155.    if ((norm(2,1)-norm(2,0)) lt 0.0) then $
  1156.       POLYFILL, [0,1,1,0], [0,0,0,0], [0,0,1,1], /NORMAL, /T3D, COLOR=2
  1157.  
  1158.    norm = [[0.0,0.0,0.0], [(-1.0),0.0,0.0]]
  1159.    norm = VERT_T3D(norm, /NO_COPY)
  1160.    if ((norm(2,1)-norm(2,0)) lt 0.0) then $
  1161.       POLYFILL, [0,0,0,0], [0,1,1,0], [0,0,1,1], /NORMAL, /T3D, COLOR=3
  1162.  
  1163.    norm = [[1.0,1.0,1.0], [1.0,1.0,2.0]]
  1164.    norm = VERT_T3D(norm, /NO_COPY)
  1165.    if ((norm(2,1)-norm(2,0)) lt 0.0) then $
  1166.       POLYFILL, [0,1,1,0], [0,0,1,1], [1,1,1,1], /NORMAL, /T3D, COLOR=1
  1167.  
  1168.    norm = [[1.0,1.0,1.0], [1.0,2.0,1.0]]
  1169.    norm = VERT_T3D(norm, /NO_COPY)
  1170.    if ((norm(2,1)-norm(2,0)) lt 0.0) then $
  1171.       POLYFILL, [0,1,1,0], [1,1,1,1], [0,0,1,1], /NORMAL, /T3D, COLOR=2
  1172.  
  1173.    norm = [[1.0,1.0,1.0], [2.0,1.0,1.0]]
  1174.    norm = VERT_T3D(norm, /NO_COPY)
  1175.    if ((norm(2,1)-norm(2,0)) lt 0.0) then $
  1176.       POLYFILL, [1,1,1,1], [0,1,1,0], [0,0,1,1], /NORMAL, /T3D, COLOR=3
  1177.  
  1178.    HANDLE_VALUE, sMainState.hBackImage, TVRD(), /SET
  1179.    HANDLE_VALUE, sMainState.hBackDepth, TVRD(CHANNEL=1, /WORDS), /SET
  1180.  
  1181.    TV, TEMPORARY(image)
  1182.    TV, TEMPORARY(depth), CHANNEL=1, /WORDS
  1183.    SET_PLOT, sMainState.screenDevice
  1184.  
  1185. end
  1186. ;******************************************************************************
  1187.  
  1188.  
  1189. ;******************************************************************************
  1190. ; Function to check out the current data.
  1191. function Viz3D_GetData, sMainState, curData
  1192.  
  1193.    if (N_ELEMENTS(curData) LE 0L) then curData = sMainState.curData
  1194.  
  1195.    HANDLE_VALUE, sMainState.hDataList, lData3D, /NO_COPY
  1196.    hData3D = lData3D(curData)
  1197.    HANDLE_VALUE, sMainState.hDataList, lData3D, /NO_COPY, /SET
  1198.  
  1199.    HANDLE_VALUE, hData3D, data3D, /NO_COPY
  1200.    return, data3D
  1201.  
  1202. end
  1203. ;******************************************************************************
  1204.  
  1205.  
  1206. ;******************************************************************************
  1207. ; Function to check in the current data.
  1208. pro Viz3D_PutData, data3D, sMainState, curData
  1209.  
  1210.    if (N_ELEMENTS(curData) LE 0L) then curData = sMainState.curData
  1211.  
  1212.    HANDLE_VALUE, sMainState.hDataList, lData3D, /NO_COPY
  1213.    hData3D = lData3D(curData)
  1214.    HANDLE_VALUE, sMainState.hDataList, lData3D, /NO_COPY, /SET
  1215.  
  1216.    HANDLE_VALUE, hData3D, data3D, /NO_COPY, /SET
  1217.  
  1218. end
  1219. ;******************************************************************************
  1220.  
  1221.  
  1222. ;******************************************************************************
  1223. ; Function to scale the data into the specified thereshold range.
  1224. function Viz3D_ScaleData, data3D, sMainState
  1225.  
  1226.    HANDLE_VALUE, sMainState.sThreshState.hLowThresh, lowThresh, /NO_COPY
  1227.    HANDLE_VALUE, sMainState.sThreshState.hHighThresh, highThresh, /NO_COPY
  1228.    lTh = lowThresh(sMainState.curData)
  1229.    hTh = highThresh(sMainState.curData)
  1230.    HANDLE_VALUE, sMainState.sThreshState.hLowThresh, lowThresh, /NO_COPY, /SET
  1231.    HANDLE_VALUE, sMainState.sThreshState.hHighThresh, highThresh, $
  1232.                  /NO_COPY, /SET
  1233.    return, BYTSCL(TEMPORARY(data3D), MIN=lTh, MAX=hTh, TOP=255B)
  1234.  
  1235. end
  1236. ;******************************************************************************
  1237.  
  1238.  
  1239. ;******************************************************************************
  1240. ; Procedure to compute the intersection outline of the cube and the
  1241. ; oblique slicing plane.   This procedure also draws the outline in
  1242. ; the current window (either the big view window, or the small slice
  1243. ; status window).
  1244. ; The VERT_PLANE keyword returns the intersection coordinates in the
  1245. ; image (oblique) plane.   The VERT_3D keyword returns the intersection
  1246. ; coordinates as absolute 3D coordinates.   The plane and 3D coordinates
  1247. ; will be necessary when drawing the data on the oblique plane.
  1248.  
  1249. pro Viz3D_DrawSliceOblique, obliqCenter, obliqNormal, fillColor, $
  1250.        edgeColor, rangeX, rangeY, rangeZ, zScale, NORMCOLOR=normColor, $
  1251.        SKIP_FILL=skipFill, VERT_PLANE=vertPlane, VERT_3D=vert3D
  1252.  
  1253.    ; Scale the oblique normal vector.
  1254.    zDim = rangeZ * zScale
  1255.    maxDim = rangeX > rangeY > zDim
  1256.    sliceNormU = obliqNormal
  1257.    sliceNormU(0) = obliqNormal(0) * rangeX / maxDim
  1258.    sliceNormU(1) = obliqNormal(1) * rangeY / maxDim
  1259.    sliceNormU(2) = obliqNormal(2) * zDim / maxDim
  1260.  
  1261.    ; Determine the rotation angles and build the transformation matrices.
  1262.  
  1263.    if ((sliceNormU(0) eq 0.0) and (sliceNormU(1) eq 0.0)) then angZ = 0.0 $
  1264.    else angZ = ATAN(sliceNormU(1), sliceNormU(0))
  1265.  
  1266.    pDistance = SQRT(sliceNormU(0)^2 + sliceNormU(1)^2)
  1267.    if ((pDistance eq 0.0) and (sliceNormU(2) eq 0.0)) then angY = 0.0 $
  1268.    else angY = ATAN(sliceNormU(2), pDistance)
  1269.  
  1270.    sZ = SIN(-angZ)
  1271.    cZ = COS(-angZ)
  1272.    sY = SIN(angY-(!PI/2.0))
  1273.    cY = COS(angY-(!PI/2.0))
  1274.  
  1275.    ident4 = FLTARR(4, 4)
  1276.    ident4([0,5,10,15]) = 1.0
  1277.  
  1278.    vTrans1 = ident4
  1279.    ; First translation.
  1280.    m4X4 = ident4
  1281.    m4X4([3,7,11]) = (-obliqCenter)
  1282.    vTrans1 = TEMPORARY(vTrans1) # m4X4
  1283.    ; Z rotation.
  1284.    m4X4 = ident4
  1285.    m4x4(0,0) = cZ
  1286.    m4x4(0,1) = sZ
  1287.    m4x4(1,0) = (-sZ)
  1288.    m4x4(1,1) = cZ
  1289.    vTrans1 = TEMPORARY(vTrans1) # m4X4
  1290.    ; Y rotation.
  1291.    m4X4 = ident4
  1292.    m4x4(0,0) = cY
  1293.    m4x4(0,2) = (-sY)
  1294.    m4x4(2,0) = sY
  1295.    m4x4(2,2) = cY
  1296.    vTrans1 = TEMPORARY(vTrans1) # m4X4
  1297.  
  1298.    sZ = SIN(angZ)
  1299.    cZ = COS(angZ)
  1300.    sY = SIN((!PI/2.0)-angY)
  1301.    cY = COS((!PI/2.0)-angY)
  1302.  
  1303.    ; Create vTrans2 as the inverse of vTrans1.
  1304.    vTrans2 = ident4
  1305.    ; Y rotation.
  1306.    m4X4 = ident4
  1307.    m4x4(0,0) = cY
  1308.    m4x4(0,2) = (-sY)
  1309.    m4x4(2,0) = sY
  1310.    m4x4(2,2) = cY
  1311.    vTrans2 = TEMPORARY(vTrans2) # m4X4
  1312.    ; Z rotation.
  1313.    m4X4 = ident4
  1314.    m4x4(0,0) = cZ
  1315.    m4x4(0,1) = sZ
  1316.    m4x4(1,0) = (-sZ)
  1317.    m4x4(1,1) = cZ
  1318.    vTrans2 = TEMPORARY(vTrans2) # m4X4
  1319.    ; First translation.
  1320.    m4X4 = ident4
  1321.    m4X4([3,7,11]) = (+obliqCenter)
  1322.    vTrans2 = TEMPORARY(vTrans2) # m4X4
  1323.  
  1324.    verts = FLTARR(3, 8, /NOZERO)
  1325.    verts(0, 0) = [0,0,0]
  1326.    verts(0, 1) = [1,0,0]
  1327.    verts(0, 2) = [1,1,0]
  1328.    verts(0, 3) = [0,1,0]
  1329.    verts(0, 4) = [0,0,1]
  1330.    verts(0, 5) = [1,0,1]
  1331.    verts(0, 6) = [1,1,1]
  1332.    verts(0, 7) = [0,1,1]
  1333.    verts = VERT_T3D(verts, /NO_COPY, MATRIX=vTrans1)
  1334.  
  1335.    ; Search for intersection points.
  1336.  
  1337.    newXYZ = [0.0, 0.0, 0.0]
  1338.  
  1339.    ; Verts 0, 1.
  1340.    if ((verts(2,0)*verts(2,1)) le 0.0) then begin
  1341.       lenFac = verts(2,0) / (verts(2,0) - verts(2,1))
  1342.       newXYZ = [Temporary(newXYZ), verts(*,0) + $
  1343.          ((verts(*,1)-verts(*,0)) * lenFac)]
  1344.    endif
  1345.    ; Verts 0, 3.
  1346.    if ((verts(2,0)*verts(2,3)) le 0.0) then begin
  1347.       lenFac = verts(2,0) / (verts(2,0) - verts(2,3))
  1348.       newXYZ = [Temporary(newXYZ), verts(*,0) + $
  1349.          ((verts(*,3)-verts(*,0)) * lenFac)]
  1350.    endif
  1351.    ; Verts 0, 4.
  1352.    if ((verts(2,0)*verts(2,4)) le 0.0) then begin
  1353.       lenFac = verts(2,0) / (verts(2,0) - verts(2,4))
  1354.       newXYZ = [Temporary(newXYZ), verts(*,0) + $
  1355.          ((verts(*,4)-verts(*,0)) * lenFac)]
  1356.    endif
  1357.    ; Verts 1, 2.
  1358.    if ((verts(2,1)*verts(2,2)) le 0.0) then begin
  1359.       lenFac = verts(2,1) / (verts(2,1) - verts(2,2))
  1360.       newXYZ = [Temporary(newXYZ), verts(*,1) + $
  1361.          ((verts(*,2)-verts(*,1)) * lenFac)]
  1362.    endif
  1363.    ; Verts 1, 5.
  1364.    if ((verts(2,1)*verts(2,5)) le 0.0) then begin
  1365.       lenFac = verts(2,1) / (verts(2,1) - verts(2,5))
  1366.       newXYZ = [Temporary(newXYZ), verts(*,1) + $
  1367.          ((verts(*,5)-verts(*,1)) * lenFac)]
  1368.    endif
  1369.    ; Verts 2, 3.
  1370.    if ((verts(2,2)*verts(2,3)) le 0.0) then begin
  1371.       lenFac = verts(2,2) / (verts(2,2) - verts(2,3))
  1372.       newXYZ = [Temporary(newXYZ), verts(*,2) + $
  1373.          ((verts(*,3)-verts(*,2)) * lenFac)]
  1374.    endif
  1375.    ; Verts 2, 6.
  1376.    if ((verts(2,2)*verts(2,6)) le 0.0) then begin
  1377.       lenFac = verts(2,2) / (verts(2,2) - verts(2,6))
  1378.       newXYZ = [Temporary(newXYZ), verts(*,2) + $
  1379.          ((verts(*,6)-verts(*,2)) * lenFac)]
  1380.    endif
  1381.    ; Verts 3, 7.
  1382.    if ((verts(2,3)*verts(2,7)) le 0.0) then begin
  1383.       lenFac = verts(2,3) / (verts(2,3) - verts(2,7))
  1384.       newXYZ = [Temporary(newXYZ), verts(*,3) + $
  1385.          ((verts(*,7)-verts(*,3)) * lenFac)]
  1386.    endif
  1387.    ; Verts 4, 5.
  1388.    if ((verts(2,4)*verts(2,5)) le 0.0) then begin
  1389.       lenFac = verts(2,4) / (verts(2,4) - verts(2,5))
  1390.       newXYZ = [Temporary(newXYZ), verts(*,4) + $
  1391.          ((verts(*,5)-verts(*,4)) * lenFac)]
  1392.    endif
  1393.    ; Verts 4, 7.
  1394.    if ((verts(2,4)*verts(2,7)) le 0.0) then begin
  1395.       lenFac = verts(2,4) / (verts(2,4) - verts(2,7))
  1396.       newXYZ = [Temporary(newXYZ), verts(*,4) + $
  1397.          ((verts(*,7)-verts(*,4)) * lenFac)]
  1398.    endif
  1399.    ; Verts 5, 6.
  1400.    if ((verts(2,5)*verts(2,6)) le 0.0) then begin
  1401.       lenFac = verts(2,5) / (verts(2,5) - verts(2,6))
  1402.       newXYZ = [Temporary(newXYZ), verts(*,5) + $
  1403.          ((verts(*,6)-verts(*,5)) * lenFac)]
  1404.    endif
  1405.    ; Verts 6, 7.
  1406.    if ((verts(2,6)*verts(2,7)) le 0.0) then begin
  1407.       lenFac = verts(2,6) / (verts(2,6) - verts(2,7))
  1408.       newXYZ = [Temporary(newXYZ), verts(*,6) + $
  1409.          ((verts(*,7)-verts(*,6)) * lenFac)]
  1410.    endif
  1411.  
  1412.    if (N_ELEMENTS(newXYZ) le 3L) then return
  1413.  
  1414.    newXYZ = newXYZ(3:*)
  1415.    nPoints = N_ELEMENTS(newXYZ) / 3
  1416.    newXYZ = REFORM(TEMPORARY(newXYZ), 3, nPoints)
  1417.  
  1418.    ; newXYZ is now a 3,n array of 3D intersection vertices.
  1419.  
  1420.    ; Sort the vertices into counter-clockwise order.
  1421.  
  1422.    newXMin = MIN(newXYZ(0,*), MAX=newXMax)
  1423.    newYMin = MIN(newXYZ(1,*), MAX=newYMax)
  1424.    cX = (newXMin + newXMax) / 2.0
  1425.    cY = (newYMin + newYMax) / 2.0
  1426.  
  1427.    angDiff = ATAN(newXYZ(1,*)-cY, newXYZ(0,*)-cX)
  1428.  
  1429.    negInd = WHERE(angDiff lt 0.0)
  1430.    if (negInd(0) ge 0L) then angDiff(negInd) = angDiff(negInd) + (2.0*!PI)
  1431.    sortInd = SORT(Temporary(angDiff))
  1432.    newXYZ = newXYZ(*, Temporary(sortInd))
  1433.  
  1434.    ; Save the intersection vertices on the image (oblique) plane.
  1435.    vertPlane = newXYZ
  1436.    ; Save the intersection vertices as 3D data coordinates.
  1437.    newXYZ = VERT_T3D(newXYZ, MATRIX=vTrans2, /NO_COPY)
  1438.    vert3D = newXYZ
  1439.    ; vertPlane and vert3D are returned to the calling procedure via
  1440.    ; the VERT_PLANE and VERT_3D keywords.
  1441.  
  1442.    ; Draw the intersection outline (optionally filled).
  1443.    if not(KEYWORD_SET(skipFill)) then $
  1444.       POLYFILL, newXYZ, /NORMAL, /T3D, COLOR=fillColor
  1445.    PLOTS, newXYZ, /NORMAL, /T3D, COLOR=edgeColor
  1446.    PLOTS, newXYZ(*,0), /NORMAL, /T3D, COLOR=edgeColor, /CONTINUE
  1447.  
  1448.    if (N_ELEMENTS(normColor) gt 0L) then begin
  1449.       ; Draw the surface normal vector.
  1450.       sliceNormU = obliqNormal
  1451.       sliceNormU(0) = obliqNormal(0) * maxDim / rangeX
  1452.       sliceNormU(1) = obliqNormal(1) * maxDim / rangeY
  1453.       sliceNormU(2) = obliqNormal(2) * maxDim / zDim
  1454.  
  1455.       normPoint = obliqCenter + sliceNormU
  1456.  
  1457.       if (normPoint(0) lt 0.0) then begin
  1458.          lenFac = obliqCenter(0) / (obliqCenter(0) - normPoint(0))
  1459.          normPoint = obliqCenter + (sliceNormU * lenFac)
  1460.       endif
  1461.       if (normPoint(0) gt 1.0) then begin
  1462.          lenFac = (1.0 - obliqCenter(0)) / (normPoint(0) - obliqCenter(0))
  1463.          normPoint = obliqCenter + (sliceNormU * lenFac)
  1464.       endif
  1465.  
  1466.       if (normPoint(1) lt 0.0) then begin
  1467.          lenFac = obliqCenter(1) / (obliqCenter(1) - normPoint(1))
  1468.          normPoint = obliqCenter + (sliceNormU * lenFac)
  1469.       endif
  1470.       if (normPoint(1) gt 1.0) then begin
  1471.          lenFac = (1.0 - obliqCenter(1)) / (normPoint(1) - obliqCenter(1))
  1472.          normPoint = obliqCenter + (sliceNormU * lenFac)
  1473.       endif
  1474.  
  1475.       if (normPoint(2) lt 0.0) then begin
  1476.          lenFac = obliqCenter(2) / (obliqCenter(2) - normPoint(2))
  1477.          normPoint = obliqCenter + (sliceNormU * lenFac)
  1478.       endif
  1479.       if (normPoint(2) gt 1.0) then begin
  1480.          lenFac = (1.0 - obliqCenter(2)) / (normPoint(2) - obliqCenter(2))
  1481.          normPoint = obliqCenter + (sliceNormU * lenFac)
  1482.       endif
  1483.  
  1484.       PLOTS, [obliqCenter(0), normPoint(0)], $
  1485.              [obliqCenter(1), normPoint(1)], $
  1486.              [obliqCenter(2), normPoint(2)], $
  1487.          /NORMAL, /T3D, COLOR=normColor
  1488.    endif
  1489.  
  1490. end
  1491. ;******************************************************************************
  1492.  
  1493.  
  1494. ;******************************************************************************
  1495. ; Procedure to draw the cube and current slicing plane outline in the
  1496. ; small slice status window.
  1497. pro Viz3D_SliceShow, sMainState
  1498.  
  1499.    fillColor = Viz3D_TransColor(sMainState, sMainState.sSliceState.fillColor)
  1500.    edgeColor = Viz3D_TransColor(sMainState, sMainState.sSliceState.edgeColor)
  1501.    normColor = Viz3D_TransColor(sMainState, sMainState.sSliceState.normColor)
  1502.    backColor = Viz3D_TransColor(sMainState, sMainState.backColor)
  1503.  
  1504.    WSET, sMainState.sSliceState.sliceWin
  1505.    ERASE
  1506.  
  1507.    case (sMainState.sSliceState.planeMode*sMainState.sSliceState.orthoDir) of
  1508.       0: begin ; Oblique
  1509.          Viz3D_DrawSliceOblique, sMainState.sSliceState.obliqCenter, $
  1510.             sMainState.sSliceState.obliqNormal, fillColor, edgeColor, $
  1511.             sMainState.sViewState.xMax, sMainState.sViewState.yMax, $
  1512.             sMainState.sViewState.zMax, sMainState.sViewState.zScale, $
  1513.             NORMCOLOR=normColor
  1514.       end
  1515.       1: begin ; X
  1516.          POLYFILL, sMainState.sSliceState.orthoPos, [0,1,1,0], [0,0,1,1], $
  1517.             /NORMAL, /T3D, COLOR=fillColor
  1518.          PLOTS, sMainState.sSliceState.orthoPos, [0,1,1,0,0], [0,0,1,1,0], $
  1519.             /NORMAL, /T3D, COLOR=edgeColor
  1520.       end
  1521.       2: begin ; Y
  1522.          POLYFILL, [0,1,1,0], sMainState.sSliceState.orthoPos, [0,0,1,1], $
  1523.             /NORMAL, /T3D, COLOR=fillColor
  1524.          PLOTS, [0,1,1,0,0], sMainState.sSliceState.orthoPos, [0,0,1,1,0], $
  1525.             /NORMAL, /T3D, COLOR=edgeColor
  1526.       end
  1527.       3: begin ; Z
  1528.          POLYFILL, [0,1,1,0], [0,0,1,1], sMainState.sSliceState.orthoPos, $
  1529.             /NORMAL, /T3D, COLOR=fillColor
  1530.          PLOTS, [0,1,1,0,0], [0,0,1,1,0], sMainState.sSliceState.orthoPos, $
  1531.             /NORMAL, /T3D, COLOR=edgeColor
  1532.       end
  1533.    endcase
  1534.  
  1535.    ; Draw the cube outline in the current window.
  1536.    Viz3D_DrawCube, sMainState, /SKIPBACK, /SKIPAXIS, /DIRECT
  1537.  
  1538.    WSET, sMainState.mainWin
  1539. end
  1540. ;******************************************************************************
  1541.  
  1542.  
  1543. ;******************************************************************************
  1544. ; Procedure to draw the cube outline in the current window,
  1545. pro Viz3D_DrawCube, sMainState, SKIPCUBE=skipCube, SKIPAXIS=skipAxis, $
  1546.     SKIPFRONT=skipFront, SKIPBACK=skipBack, DIRECT=directDraw, AXIS=drawAxis
  1547.  
  1548.    axisOn = sMainState.axisOn
  1549.    if (KEYWORD_SET(drawAxis)) then axisOn = 1
  1550.  
  1551.    cubeColor = Viz3D_TransColor(sMainState, sMainState.cubeColor)
  1552.    axisColor = Viz3D_TransColor(sMainState, sMainState.axisColor)
  1553.  
  1554.    if ((axisOn) and not(KEYWORD_SET(skipAxis))) then $
  1555.       lineColor = axisColor else lineColor = cubeColor
  1556.  
  1557.    verts = FLTARR(3, 8, /NOZERO)
  1558.    verts(0, 0) = [0,0,0]
  1559.    verts(0, 1) = [1,0,0]
  1560.    verts(0, 2) = [1,1,0]
  1561.    verts(0, 3) = [0,1,0]
  1562.    verts(0, 4) = [0,0,1]
  1563.    verts(0, 5) = [1,0,1]
  1564.    verts(0, 6) = [1,1,1]
  1565.    verts(0, 7) = [0,1,1]
  1566.    verts = VERT_T3D(verts, /NO_COPY)
  1567.  
  1568.    cubeDrawn = 0
  1569.    if (((sMainState.cubeOn) and not(KEYWORD_SET(skipCube))) or $
  1570.       KEYWORD_SET(directDraw)) then begin
  1571.       ; Draw the cube.
  1572.  
  1573.       cubeDrawn = 1
  1574.       lCol = [lineColor, lineColor, cubeColor, cubeColor, lineColor]
  1575.  
  1576.       if not(KEYWORD_SET(skipBack)) then begin
  1577.          ; Draw the "hidden" lines as dotted.
  1578.  
  1579.          cp = CROSSP(verts(*,1)-verts(*,0), verts(*,4)-verts(*,0))
  1580.          hideFace0154 = (cp(2) lt 0.0)
  1581.          cp = CROSSP(verts(*,4)-verts(*,0), verts(*,3)-verts(*,0))
  1582.          hideFace0473 = (cp(2) lt 0.0)
  1583.          cp = CROSSP(verts(*,3)-verts(*,0), verts(*,1)-verts(*,0))
  1584.          hideFace0321 = (cp(2) lt 0.0)
  1585.          cp = CROSSP(verts(*,2)-verts(*,6), verts(*,7)-verts(*,6))
  1586.          hideFace6237 = (cp(2) lt 0.0)
  1587.          cp = CROSSP(verts(*,5)-verts(*,6), verts(*,2)-verts(*,6))
  1588.          hideFace6514 = (cp(2) lt 0.0)
  1589.          cp = CROSSP(verts(*,7)-verts(*,6), verts(*,5)-verts(*,6))
  1590.          hideFace6745 = (cp(2) lt 0.0)
  1591.  
  1592.          if (hideFace0154 and hideFace0321) then $
  1593.             PLOTS, verts(*, [0,1]), /NORMAL, T3D=0, COLOR=lineColor, $
  1594.                LINESTYLE=1
  1595.          if (hideFace0473 and hideFace0321) then $
  1596.             PLOTS, verts(*, [0,3]), /NORMAL, T3D=0, COLOR=lineColor, $
  1597.                LINESTYLE=1
  1598.          if (hideFace0154 and hideFace0473) then $
  1599.             PLOTS, verts(*, [0,4]), /NORMAL, T3D=0, COLOR=lineColor, $
  1600.                LINESTYLE=1
  1601.  
  1602.          if (hideFace0321 and hideFace6514) then $
  1603.             PLOTS, verts(*, [1,2]), /NORMAL, T3D=0, COLOR=cubeColor, $
  1604.                LINESTYLE=1
  1605.          if (hideFace0321 and hideFace6237) then $
  1606.             PLOTS, verts(*, [2,3]), /NORMAL, T3D=0, COLOR=cubeColor, $
  1607.                LINESTYLE=1
  1608.          if (hideFace0154 and hideFace6514) then $
  1609.             PLOTS, verts(*, [1,5]), /NORMAL, T3D=0, COLOR=cubeColor, $
  1610.                LINESTYLE=1
  1611.          if (hideFace0473 and hideFace6237) then $
  1612.             PLOTS, verts(*, [3,7]), /NORMAL, T3D=0, COLOR=cubeColor, $
  1613.                LINESTYLE=1
  1614.          if (hideFace6745 and hideFace0473) then $
  1615.             PLOTS, verts(*, [4,7]), /NORMAL, T3D=0, COLOR=cubeColor, $
  1616.                LINESTYLE=1
  1617.          if (hideFace6745 and hideFace0154) then $
  1618.             PLOTS, verts(*, [4,5]), /NORMAL, T3D=0, COLOR=cubeColor, $
  1619.                LINESTYLE=1
  1620.          if (hideFace6745 and hideFace6514) then $
  1621.             PLOTS, verts(*, [5,6]), /NORMAL, T3D=0, COLOR=cubeColor, $
  1622.                LINESTYLE=1
  1623.          if (hideFace6745 and hideFace6237) then $
  1624.             PLOTS, verts(*, [6,7]), /NORMAL, T3D=0, COLOR=cubeColor, $
  1625.                LINESTYLE=1
  1626.          if (hideFace6514 and hideFace6237) then $
  1627.             PLOTS, verts(*, [2,6]), /NORMAL, T3D=0, COLOR=cubeColor, $
  1628.                LINESTYLE=1
  1629.       endif
  1630.  
  1631.       if not(KEYWORD_SET(skipFront)) then begin
  1632.          ; Draw the remaining cube edges as solid (linestyle 0).
  1633.  
  1634.          cp = CROSSP(verts(*,1)-verts(*,0), verts(*,4)-verts(*,0))
  1635.          if (cp(2) gt 0.0) then $
  1636.             PLOTS, verts(*, [0,1,5,4,0]), /NORMAL, T3D=0, COLOR=lCol
  1637.  
  1638.          cp = CROSSP(verts(*,4)-verts(*,0), verts(*,3)-verts(*,0))
  1639.          if (cp(2) gt 0.0) then $
  1640.             PLOTS, verts(*, [0,4,7,3,0]), /NORMAL, T3D=0, COLOR=lCol
  1641.  
  1642.          cp = CROSSP(verts(*,3)-verts(*,0), verts(*,1)-verts(*,0))
  1643.          if (cp(2) gt 0.0) then $
  1644.             PLOTS, verts(*, [0,3,2,1,0]), /NORMAL, T3D=0, COLOR=lCol
  1645.  
  1646.          cp = CROSSP(verts(*,7)-verts(*,6), verts(*,5)-verts(*,6))
  1647.          if (cp(2) gt 0.0) then $
  1648.             PLOTS, verts(*, [6,7,4,5,6]), /NORMAL, T3D=0, COLOR=cubeColor
  1649.  
  1650.          cp = CROSSP(verts(*,5)-verts(*,6), verts(*,2)-verts(*,6))
  1651.          if (cp(2) gt 0.0) then $
  1652.             PLOTS, verts(*, [6,5,1,2,6]), /NORMAL, T3D=0, COLOR=cubeColor
  1653.  
  1654.          cp = CROSSP(verts(*,2)-verts(*,6), verts(*,7)-verts(*,6))
  1655.          if (cp(2) gt 0.0) then $
  1656.             PLOTS, verts(*, [6,2,3,7,6]), /NORMAL, T3D=0, COLOR=cubeColor
  1657.       endif
  1658.    endif
  1659.  
  1660.    if (((axisOn) and not(KEYWORD_SET(skipAxis))) and $
  1661.       (not(KEYWORD_SET(skipFront)) and not(KEYWORD_SET(directDraw)))) $
  1662.       then begin
  1663.       ; Draw the axis.
  1664.  
  1665.       if (cubeDrawn eq 0) then begin
  1666.          PLOTS, verts(*, [0,1]), /NORMAL, T3D=0, COLOR=axisColor
  1667.          PLOTS, verts(*, [0,3]), /NORMAL, T3D=0, COLOR=axisColor
  1668.          PLOTS, verts(*, [0,4]), /NORMAL, T3D=0, COLOR=axisColor
  1669.       endif
  1670.  
  1671.       cp = CROSSP(verts(*,5)-verts(*,1), verts(*,0)-verts(*,1))
  1672.       showPlane1 = (cp(2) gt 0.0)
  1673.       cp = CROSSP(verts(*,0)-verts(*,1), verts(*,2)-verts(*,1))
  1674.       showPlane2 = (cp(2) gt 0.0)
  1675.       cp = CROSSP(verts(*,2)-verts(*,1), verts(*,5)-verts(*,1))
  1676.       showPlane3 = (cp(2) gt 0.0)
  1677.       if ((showPlane1+showPlane2+showPlane3) ge 1) then begin
  1678.          PLOTS, [0.95,1.0,0.95], [0.01, 0.0, -0.01], [0,0,0], /NORMAL, $
  1679.             /T3D, COLOR=axisColor
  1680.          PLOTS, [0.95,1.0,0.95], [0,0,0], [0.01, 0.0, -0.01], /NORMAL, $
  1681.             /T3D, COLOR=axisColor
  1682.          XYOUTS, 1.05, 0.0, Z=0.0, 'X', /NORMAL, /T3D, $
  1683.             CHARSIZE=24.0/FLOAT(!D.Y_Ch_Size), COLOR=axisColor, $
  1684.             ALIGNMENT=0.5, TEXT_AXES=2
  1685.       endif
  1686.  
  1687.       cp = CROSSP(verts(*,0)-verts(*,3), verts(*,7)-verts(*,3))
  1688.       showPlane1 = (cp(2) gt 0.0)
  1689.       cp = CROSSP(verts(*,7)-verts(*,3), verts(*,2)-verts(*,3))
  1690.       showPlane2 = (cp(2) gt 0.0)
  1691.       cp = CROSSP(verts(*,2)-verts(*,3), verts(*,0)-verts(*,3))
  1692.       showPlane3 = (cp(2) gt 0.0)
  1693.       if ((showPlane1+showPlane2+showPlane3) ge 1) then begin
  1694.          PLOTS, [0.01, 0.0, -0.01], [0.95,1.0,0.95], [0,0,0], /NORMAL, $
  1695.             /T3D, COLOR=axisColor
  1696.          PLOTS, [0,0,0], [0.95,1.0,0.95], [0.01, 0.0, -0.01], /NORMAL, $
  1697.             /T3D, COLOR=axisColor
  1698.          XYOUTS, 0.0, 1.05, Z=0.0, 'Y', /NORMAL, /T3D, $
  1699.             CHARSIZE=24.0/FLOAT(!D.Y_Ch_Size), COLOR=axisColor, $
  1700.             ALIGNMENT=0.5, TEXT_AXES=1
  1701.       endif
  1702.  
  1703.       cp = CROSSP(verts(*,5)-verts(*,4), verts(*,7)-verts(*,4))
  1704.       showPlane1 = (cp(2) gt 0.0)
  1705.       cp = CROSSP(verts(*,7)-verts(*,4), verts(*,0)-verts(*,4))
  1706.       showPlane2 = (cp(2) gt 0.0)
  1707.       cp = CROSSP(verts(*,0)-verts(*,4), verts(*,5)-verts(*,4))
  1708.       showPlane3 = (cp(2) gt 0.0)
  1709.       if ((showPlane1+showPlane2+showPlane3) ge 1) then begin
  1710.          PLOTS, [0,0,0], [0.01, 0.0, -0.01], [0.95,1.0,0.95], /NORMAL, $
  1711.             /T3D, COLOR=axisColor
  1712.          PLOTS, [0.01, 0.0, -0.01], [0,0,0], [0.95,1.0,0.95], /NORMAL, $
  1713.             /T3D, COLOR=axisColor
  1714.          XYOUTS, 0.0, 0.0, Z=1.05, 'Z', /NORMAL, /T3D, $
  1715.             CHARSIZE=24.0/FLOAT(!D.Y_Ch_Size), COLOR=axisColor, $
  1716.             ALIGNMENT=0.5, TEXT_AXES=0
  1717.       endif
  1718.    endif
  1719.  
  1720.    EMPTY
  1721.  
  1722. end
  1723. ;******************************************************************************
  1724.  
  1725.  
  1726. ;******************************************************************************
  1727. pro Viz3D_DrawData, sMainState
  1728.  
  1729.    SET_PLOT, 'Z'
  1730.    Viz3D_DrawCube, sMainState, /SKIPFRONT
  1731.    img = TVRD()
  1732.    SET_PLOT, sMainState.screenDevice
  1733.    WSET, sMainState.pixWin
  1734.    if (sMainState.sColorState.displayBits eq 8) then $
  1735.       TV, TEMPORARY(img) $
  1736.    else begin
  1737.       img3 = BYTARR(3, sMainState.winX, sMainState.winY, /NOZERO)
  1738.       img3(0, *, *) = sMainState.sColorState.cR(img)
  1739.       img3(1, *, *) = sMainState.sColorState.cG(img)
  1740.       img3(2, *, *) = sMainState.sColorState.cB(Temporary(img))
  1741.       TV, Temporary(img3), TRUE=1
  1742.    endelse
  1743.    Viz3D_DrawCube, sMainState, /SKIPBACK
  1744.    EMPTY
  1745.    WSET, sMainState.mainWin
  1746.    DEVICE, COPY=[0, 0, sMainState.winX, sMainState.winY, 0, 0, $
  1747.                  sMainState.pixWin]
  1748.    sMainState.cleanupView = 0
  1749.    sMainState.cleanupBuffer = 0
  1750.  
  1751. end
  1752. ;******************************************************************************
  1753.  
  1754.  
  1755. ;******************************************************************************
  1756. ; Procedure to draw the block outline.
  1757. pro Viz3D_BlockShow, sMainState, DIRECT=directDraw
  1758.  
  1759.    if not(KEYWORD_SET(directDraw)) then $
  1760.       WSET, sMainState.sBlockState.blockWin
  1761.  
  1762.    x1 = sMainState.sBlockState.c1(0)
  1763.    y1 = sMainState.sBlockState.c1(1)
  1764.    z1 = sMainState.sBlockState.c1(2)
  1765.    x2 = sMainState.sBlockState.c2(0)
  1766.    y2 = sMainState.sBlockState.c2(1)
  1767.    z2 = sMainState.sBlockState.c2(2)
  1768.    blockColor = $
  1769.       Viz3D_TransColor(sMainState, sMainState.sBlockState.blockColor)
  1770.  
  1771.    ; Draw the cube outline in the current window.
  1772.    if not(KEYWORD_SET(directDraw)) then begin
  1773.       ERASE
  1774.       Viz3D_DrawCube, sMainState, /DIRECT, /AXIS
  1775.    endif else begin
  1776.  
  1777.       c1Color = Viz3D_TransColor(sMainState, sMainState.sBlockState.c1Color)
  1778.       c2Color = Viz3D_TransColor(sMainState, sMainState.sBlockState.c2Color)
  1779.       xM = sMainState.sViewState.xMax
  1780.       yM = sMainState.sViewState.yMax
  1781.       zM = sMainState.sViewState.zMax
  1782.  
  1783.       norm = [[x1,y1,z1], [x1,y1,z1-1]]
  1784.       norm = VERT_T3D(norm, /NO_COPY)
  1785.       if ((norm(2,1)-norm(2,0)) gt 0.0) then begin
  1786.          PLOTS, [x1,x1], [y1,y1], [z1, 0], /DATA, /T3D, COLOR=c1Color
  1787.          PLOTS, [x1,x1], [y1,y1], [z1,zM], /DATA, /T3D, COLOR=c1Color, $
  1788.             LINESTYLE=1
  1789.       endif else begin
  1790.          PLOTS, [x1,x1], [y1,y1], [z1, 0], /DATA, /T3D, COLOR=c1Color, $
  1791.             LINESTYLE=1
  1792.          PLOTS, [x1,x1], [y1,y1], [z1,zM], /DATA, /T3D, COLOR=c1Color
  1793.       endelse
  1794.       norm = [[x1,y1,z1], [x1,y1-1,z1]]
  1795.       norm = VERT_T3D(norm, /NO_COPY)
  1796.       if ((norm(2,1)-norm(2,0)) gt 0.0) then begin
  1797.          PLOTS, [x1,x1], [y1, 0], [z1,z1], /DATA, /T3D, COLOR=c1Color
  1798.          PLOTS, [x1,x1], [y1,yM], [z1,z1], /DATA, /T3D, COLOR=c1Color, $
  1799.             LINESTYLE=1
  1800.       endif else begin
  1801.          PLOTS, [x1,x1], [y1, 0], [z1,z1], /DATA, /T3D, COLOR=c1Color, $
  1802.             LINESTYLE=1
  1803.          PLOTS, [x1,x1], [y1,yM], [z1,z1], /DATA, /T3D, COLOR=c1Color
  1804.       endelse
  1805.       norm = [[x1,y1,z1], [x1-1,y1,z1]]
  1806.       norm = VERT_T3D(norm, /NO_COPY)
  1807.       if ((norm(2,1)-norm(2,0)) gt 0.0) then begin
  1808.          PLOTS, [x1, 0], [y1,y1], [z1,z1], /DATA, /T3D, COLOR=c1Color
  1809.          PLOTS, [x1,xM], [y1,y1], [z1,z1], /DATA, /T3D, COLOR=c1Color, $
  1810.             LINESTYLE=1
  1811.       endif else begin
  1812.          PLOTS, [x1, 0], [y1,y1], [z1,z1], /DATA, /T3D, COLOR=c1Color, $
  1813.             LINESTYLE=1
  1814.          PLOTS, [x1,xM], [y1,y1], [z1,z1], /DATA, /T3D, COLOR=c1Color
  1815.       endelse
  1816.  
  1817.       norm = [[x1,y1,z1], [x1,y1,z1-1]]
  1818.       norm = VERT_T3D(norm, /NO_COPY)
  1819.       if ((norm(2,1)-norm(2,0)) gt 0.0) then begin
  1820.          PLOTS, [x2,x2], [y2,y2], [z2, 0], /DATA, /T3D, COLOR=c2Color
  1821.          PLOTS, [x2,x2], [y2,y2], [z2,zM], /DATA, /T3D, COLOR=c2Color, $
  1822.             LINESTYLE=1
  1823.       endif else begin
  1824.          PLOTS, [x2,x2], [y2,y2], [z2, 0], /DATA, /T3D, COLOR=c2Color, $
  1825.             LINESTYLE=1
  1826.          PLOTS, [x2,x2], [y2,y2], [z2,zM], /DATA, /T3D, COLOR=c2Color
  1827.       endelse
  1828.       norm = [[x1,y1,z1], [x1,y1-1,z1]]
  1829.       norm = VERT_T3D(norm, /NO_COPY)
  1830.       if ((norm(2,1)-norm(2,0)) gt 0.0) then begin
  1831.          PLOTS, [x2,x2], [y2, 0], [z2,z2], /DATA, /T3D, COLOR=c2Color
  1832.          PLOTS, [x2,x2], [y2,yM], [z2,z2], /DATA, /T3D, COLOR=c2Color, $
  1833.             LINESTYLE=1
  1834.       endif else begin
  1835.          PLOTS, [x2,x2], [y2, 0], [z2,z2], /DATA, /T3D, COLOR=c2Color, $
  1836.             LINESTYLE=1
  1837.          PLOTS, [x2,x2], [y2,yM], [z2,z2], /DATA, /T3D, COLOR=c2Color
  1838.       endelse
  1839.       norm = [[x1,y1,z1], [x1-1,y1,z1]]
  1840.       norm = VERT_T3D(norm, /NO_COPY)
  1841.       if ((norm(2,1)-norm(2,0)) gt 0.0) then begin
  1842.          PLOTS, [x2, 0], [y2,y2], [z2,z2], /DATA, /T3D, COLOR=c2Color
  1843.          PLOTS, [x2,xM], [y2,y2], [z2,z2], /DATA, /T3D, COLOR=c2Color, $
  1844.             LINESTYLE=1
  1845.       endif else begin
  1846.          PLOTS, [x2, 0], [y2,y2], [z2,z2], /DATA, /T3D, COLOR=c2Color, $
  1847.             LINESTYLE=1
  1848.          PLOTS, [x2,xM], [y2,y2], [z2,z2], /DATA, /T3D, COLOR=c2Color
  1849.       endelse
  1850.  
  1851.    endelse
  1852.  
  1853.    PLOTS, [x1,x2,x2,x1,x1], [y1,y1,y2,y2,y1], [z1,z1,z1,z1,z1], $
  1854.       /DATA, /T3D, COLOR=blockColor
  1855.    PLOTS, [x1,x2,x2,x1,x1], [y1,y1,y2,y2,y1], [z2,z2,z2,z2,z2], $
  1856.       /DATA, /T3D, COLOR=blockColor
  1857.    PLOTS, [x1,x1], [y1,y1], [z1,z2], /DATA, /T3D, COLOR=blockColor
  1858.    PLOTS, [x2,x2], [y1,y1], [z1,z2], /DATA, /T3D, COLOR=blockColor
  1859.    PLOTS, [x2,x2], [y2,y2], [z1,z2], /DATA, /T3D, COLOR=blockColor
  1860.    PLOTS, [x1,x1], [y2,y2], [z1,z2], /DATA, /T3D, COLOR=blockColor
  1861.  
  1862.    EMPTY
  1863.  
  1864.    if not(KEYWORD_SET(directDraw)) then $
  1865.       WSET, sMainState.mainWin
  1866.  
  1867. end
  1868. ;******************************************************************************
  1869.  
  1870.  
  1871. ;******************************************************************************
  1872. ; Procedure to draw the cube in the small view window.
  1873. pro Viz3D_ViewShow, sMainState
  1874.  
  1875.    WSET, sMainState.sViewState.viewWin
  1876.  
  1877.    ; Draw the cube outline in the current window.
  1878.    ERASE
  1879.    Viz3D_DrawCube, sMainState, /DIRECT, /AXIS
  1880.  
  1881.    WSET, sMainState.mainWin
  1882.  
  1883. end
  1884. ;******************************************************************************
  1885.  
  1886.  
  1887. ;******************************************************************************
  1888. ; Procedure to draw the histogram and threshold value in the
  1889. ; small iso-surface window.
  1890. pro Viz3D_SurfShow, sMainState, CALC_HIST=calcHist
  1891.  
  1892.    WSET, sMainState.sSurfState.surfWin
  1893.  
  1894.    tColor = Viz3D_TransColor(sMainState, sMainState.sSurfState.tColor)
  1895.    histColor = Viz3D_TransColor(sMainState, sMainState.sSurfState.histColor)
  1896.    axisColor = Viz3D_TransColor(sMainState, sMainState.sSurfState.axisColor)
  1897.  
  1898.    saveP = !P
  1899.    saveX = !X
  1900.    saveY = !Y
  1901.    saveZ = !Z
  1902.  
  1903.    x1 = 0.03
  1904.    y1 = 0.05
  1905.    x2 = 0.97
  1906.    y2 = 0.95
  1907.  
  1908.    HANDLE_VALUE, sMainState.sThreshState.hLowThresh, lowThresh, /NO_COPY
  1909.    HANDLE_VALUE, sMainState.sThreshState.hHighThresh, highThresh, /NO_COPY
  1910.    lTh = lowThresh(sMainState.curData)
  1911.    hTh = highThresh(sMainState.curData)
  1912.    HANDLE_VALUE, sMainState.sThreshState.hLowThresh, lowThresh, /NO_COPY, /SET
  1913.    HANDLE_VALUE, sMainState.sThreshState.hHighThresh, highThresh, $
  1914.                  /NO_COPY, /SET
  1915.    HANDLE_VALUE, sMainState.sSurfState.hSurfThresh, surfThresh, /NO_COPY
  1916.    surfThresh(sMainState.curData) = $
  1917.       (surfThresh(sMainState.curData) > lTh) < hTh
  1918.    sT = surfThresh(sMainState.curData)
  1919.    HANDLE_VALUE, sMainState.sSurfState.hSurfThresh, surfThresh, /NO_COPY, /SET
  1920.  
  1921.    tPos = (sT - lTh) / (hTh - lTh)
  1922.    tPos = (tPos * (x2-x1)) + x1
  1923.  
  1924.    HANDLE_VALUE, sMainState.sSurfState.hRangeHist, lRangeHist, /NO_COPY
  1925.    HANDLE_VALUE, lRangeHist(sMainState.curData), rangeHist, /NO_COPY
  1926.  
  1927.    if (KEYWORD_SET(calcHist)) then begin
  1928.       data3D = Viz3D_GetData(sMainState)
  1929.       bSize = (hTh - lTh) / 200.0
  1930.       rangeHist = $
  1931.          HISTOGRAM(FLOAT(data3D), MIN=lTh, MAX=hTh, $
  1932.             BINSIZE=bSize) > 1.0
  1933.       rangeHist = ALOG(FLOAT(TEMPORARY(rangeHist))) > 0.0
  1934.       Viz3D_PutData, data3D, sMainState
  1935.  
  1936.       PLOT, rangeHist, T3D=0, /DATA, XSTYLE=5, YSTYLE=5, /NODATA, $
  1937.          POSITION=[x1,y1,x2,y2], MIN_VALUE=1.0
  1938.       PLOTS, [x1,x2,x2,x1,x1], [y1,y1,y2,y2,y1], T3D=0, $
  1939.          /NORMAL, COLOR=axisColor
  1940.       OPLOT, rangeHist, T3D=0, COLOR=histColor, MIN_VALUE=1.0, PSYM=3
  1941.    
  1942.       WSET, sMainState.sSurfState.surfPix
  1943.       DEVICE, COPY=[0, 0, 192, 128, 0, 0, sMainState.sSurfState.surfWin]
  1944.       WSET, sMainState.sSurfState.surfWin
  1945.  
  1946.    endif else begin
  1947.       PLOT, rangeHist, T3D=0, /DATA, XSTYLE=5, YSTYLE=5, /NODATA, $
  1948.          POSITION=[x1,y1,x2,y2], MIN_VALUE=1.0, /NOERASE
  1949.       DEVICE, COPY=[0, 0, 192, 128, 0, 0, sMainState.sSurfState.surfPix]
  1950.    endelse
  1951.  
  1952.    PLOTS, [tPos, tPos], [y1, y2], T3D=0, /NORMAL, COLOR=tColor
  1953.    EMPTY
  1954.  
  1955.    HANDLE_VALUE, lRangeHist(sMainState.curData), rangeHist, /NO_COPY, /SET
  1956.    HANDLE_VALUE, sMainState.sSurfState.hRangeHist, lRangeHist, /NO_COPY, /SET
  1957.  
  1958.    WIDGET_CONTROL, sMainState.sSurfState.wSurfText, $
  1959.       SET_VALUE=STRTRIM(STRING(sT),2)
  1960.  
  1961.    !P = TEMPORARY(saveP)
  1962.    !X = TEMPORARY(saveX)
  1963.    !Y = TEMPORARY(saveY)
  1964.    !Z = TEMPORARY(saveZ)
  1965.  
  1966.    WSET, sMainState.mainWin
  1967. end
  1968. ;******************************************************************************
  1969.  
  1970.  
  1971. ;******************************************************************************
  1972. ; Procedure to draw the histogram and threshold values in the
  1973. ; small threshold window.
  1974. pro Viz3D_ThreshShow, sMainState, DYNAMIC=dynUpdate
  1975.  
  1976.    WSET, sMainState.sThreshState.threshWin
  1977.    lowColor = Viz3D_TransColor(sMainState, sMainState.sThreshState.lowColor)
  1978.    highColor = Viz3D_TransColor(sMainState, sMainState.sThreshState.highColor)
  1979.    transColor = $
  1980.       Viz3D_TransColor(sMainState, sMainState.sThreshState.transColor)
  1981.    histColor = Viz3D_TransColor(sMainState, sMainState.sThreshState.histColor)
  1982.    axisColor = Viz3D_TransColor(sMainState, sMainState.sThreshState.axisColor)
  1983.    backColor = Viz3D_TransColor(sMainState, 0)
  1984.  
  1985.    saveP = !P
  1986.    saveX = !X
  1987.    saveY = !Y
  1988.    saveZ = !Z
  1989.  
  1990.    x1 = 0.03
  1991.    y1 = 0.05
  1992.    x2 = 0.97
  1993.    y2 = 0.95
  1994.  
  1995.    HANDLE_VALUE, sMainState.sThreshState.hLowThresh, lowThresh, /NO_COPY
  1996.    HANDLE_VALUE, sMainState.sThreshState.hHighThresh, highThresh, /NO_COPY
  1997.    HANDLE_VALUE, sMainState.sThreshState.hTransVal, transVal, /NO_COPY
  1998.    lTh = lowThresh(sMainState.curData)
  1999.    hTh = highThresh(sMainState.curData)
  2000.    vTp = transVal(sMainState.curData)
  2001.    HANDLE_VALUE, sMainState.sThreshState.hLowThresh, lowThresh, $
  2002.                  /NO_COPY, /SET
  2003.    HANDLE_VALUE, sMainState.sThreshState.hHighThresh, highThresh, $
  2004.                  /NO_COPY, /SET
  2005.    HANDLE_VALUE, sMainState.sThreshState.hTransVal, transVal, $
  2006.                  /NO_COPY, /SET
  2007.  
  2008.    HANDLE_VALUE, sMainState.sThreshState.hMinData, minData, /NO_COPY
  2009.    HANDLE_VALUE, sMainState.sThreshState.hMaxData, maxData, /NO_COPY
  2010.    minD = minData(sMainState.curData)
  2011.    maxD = maxData(sMainState.curData)
  2012.    HANDLE_VALUE, sMainState.sThreshState.hMinData, minData, /NO_COPY, /SET
  2013.    HANDLE_VALUE, sMainState.sThreshState.hMaxData, maxData, /NO_COPY, /SET
  2014.  
  2015.    lowPos = (lTh - minD) / (maxD - minD)
  2016.    lowPos = (lowPos * (x2-x1)) + x1
  2017.    highPos = (hTh - minD) / (maxD - minD)
  2018.    highPos = (highPos * (x2-x1)) + x1
  2019.  
  2020.    transPos = (vTp - minD) / (maxD - minD)
  2021.    transPos = (transPos * (x2-x1)) + x1
  2022.  
  2023.    HANDLE_VALUE, sMainState.sThreshState.hDataHist, lDataHist, /NO_COPY
  2024.    HANDLE_VALUE, lDataHist(sMainState.curData), DataHist, /NO_COPY
  2025.  
  2026.    if (KEYWORD_SET(dynUpdate)) then begin
  2027.       PLOT, dataHist, T3D=0, /DATA, XSTYLE=5, YSTYLE=5, /NODATA, $
  2028.          POSITION=[x1,y1,x2,y2], MIN_VALUE=1.0, /NOERASE
  2029.       DEVICE, COPY=[0, 0, 192, 128, 0, 0, sMainState.sThreshState.threshPix]
  2030.    endif else begin
  2031.       PLOT, dataHist, T3D=0, /DATA, XSTYLE=5, YSTYLE=5, /NODATA, $
  2032.          POSITION=[x1,y1,x2,y2], MIN_VALUE=1.0
  2033.       PLOTS, [x1,x2,x2,x1,x1], [y1,y1,y2,y2,y1], T3D=0, /NORMAL, COLOR=axisColor
  2034.       OPLOT, dataHist, T3D=0, COLOR=histColor, MIN_VALUE=1.0, PSYM=3
  2035.  
  2036.       WSET, sMainState.sThreshState.threshPix
  2037.       DEVICE, COPY=[0, 0, 192, 128, 0, 0, sMainState.sThreshState.threshWin]
  2038.       WSET, sMainState.sThreshState.threshWin
  2039.  
  2040.    endelse
  2041.  
  2042.    PLOTS, [transPos, transPos], [y1, y2], T3D=0, /NORMAL, COLOR=transColor
  2043.    PLOTS, [transPos, transPos], [y1, y2], T3D=0, /NORMAL, COLOR=backColor, $
  2044.           LINESTYLE=1
  2045.    PLOTS, [lowPos, lowPos], [y1, y2], T3D=0, /NORMAL, COLOR=lowColor
  2046.    PLOTS, [highPos, highPos], [y1, y2], T3D=0, /NORMAL, COLOR=highColor
  2047.  
  2048.    HANDLE_VALUE, lDataHist(sMainState.curData), DataHist, /NO_COPY, /SET
  2049.    HANDLE_VALUE, sMainState.sThreshState.hDataHist, lDataHist, /NO_COPY, /SET
  2050.  
  2051.    WIDGET_CONTROL, sMainState.sThreshState.wThreshLowText, $
  2052.       SET_VALUE=STRTRIM(STRING(lTh),2)
  2053.    WIDGET_CONTROL, sMainState.sThreshState.wThreshHighText, $
  2054.       SET_VALUE=STRTRIM(STRING(hTh),2)
  2055.    WIDGET_CONTROL, sMainState.sThreshState.wThreshTransText, $
  2056.       SET_VALUE=STRTRIM(STRING(vTp),2)
  2057.  
  2058.    !P = TEMPORARY(saveP)
  2059.    !X = TEMPORARY(saveX)
  2060.    !Y = TEMPORARY(saveY)
  2061.    !Z = TEMPORARY(saveZ)
  2062.  
  2063.    WSET, sMainState.mainWin
  2064. end
  2065. ;******************************************************************************
  2066.  
  2067.  
  2068. ;******************************************************************************
  2069. ; Procedure to plot profile data in the small profile window.
  2070. pro Viz3D_ProfShow, sMainState, DIRECT=directDraw
  2071.  
  2072.    lineColor = Viz3D_TransColor(sMainState, sMainState.sProfState.lineColor)
  2073.    axisColor = Viz3D_TransColor(sMainState, sMainState.sProfState.axisColor)
  2074.    markColor1 = Viz3D_TransColor(sMainState, sMainState.sProfState.markColor1)
  2075.    markColor2 = Viz3D_TransColor(sMainState, sMainState.sProfState.markColor2)
  2076.  
  2077.    data3D = Viz3D_GetData(sMainState)
  2078.  
  2079.    if (sMainState.sProfState.profType eq 0) then begin ; Orthogonal profile.
  2080.       case sMainState.sProfState.profDir of
  2081.          1: begin
  2082.                profData = data3D(sMainState.sProfState.x1Ortho, $
  2083.                                sMainState.sProfState.y1Ortho, *)
  2084.                yData = FINDGEN(sMainState.szData(3))
  2085.             end
  2086.          2: begin
  2087.                profData = data3D(sMainState.sProfState.x1Ortho, *, $
  2088.                                sMainState.sProfState.z1Ortho)
  2089.                yData = FINDGEN(sMainState.szData(2))
  2090.             end
  2091.          3: begin
  2092.                profData = data3D(*, sMainState.sProfState.y1Ortho, $
  2093.                                sMainState.sProfState.z1Ortho)
  2094.                yData = FINDGEN(sMainState.szData(1))
  2095.             end
  2096.       endcase
  2097.    endif else begin ; Oblique profile.
  2098.       samples = MAX(sMainState.szData(1:3)) * 2
  2099.       yData = FINDGEN(samples)
  2100.       xInter = yData / FLOAT(samples - 1)
  2101.       yInter = xInter
  2102.       zInter = xInter
  2103.       xInter = ((sMainState.sProfState.x2Obliq - $
  2104.                  sMainState.sProfState.x1Obliq) * $
  2105.                 TEMPORARY(xInter)) + sMainState.sProfState.x1Obliq
  2106.       yInter = ((sMainState.sProfState.y2Obliq - $
  2107.                  sMainState.sProfState.y1Obliq) * $
  2108.                 TEMPORARY(yInter)) + sMainState.sProfState.y1Obliq
  2109.       zInter = ((sMainState.sProfState.z2Obliq - $
  2110.                  sMainState.sProfState.z1Obliq) * $
  2111.                 TEMPORARY(zInter)) + sMainState.sProfState.z1Obliq
  2112.       profData = INTERPOLATE(data3D, TEMPORARY(xInter), $
  2113.                     TEMPORARY(yInter), TEMPORARY(zInter))
  2114.    endelse
  2115.  
  2116.    Viz3D_PutData, data3D, sMainState
  2117.  
  2118.    saveP = !P
  2119.    saveX = !X
  2120.    saveY = !Y
  2121.    saveZ = !Z
  2122.  
  2123.    maxY = N_ELEMENTS(yData) - 1
  2124.  
  2125.    HANDLE_VALUE, sMainState.sThreshState.hLowThresh, lowThresh, /NO_COPY
  2126.    HANDLE_VALUE, sMainState.sThreshState.hHighThresh, highThresh, /NO_COPY
  2127.    lTh = lowThresh(sMainState.curData)
  2128.    hTh = highThresh(sMainState.curData)
  2129.    HANDLE_VALUE, sMainState.sThreshState.hLowThresh, lowThresh, $
  2130.                  /NO_COPY, /SET
  2131.    HANDLE_VALUE, sMainState.sThreshState.hHighThresh, highThresh, $
  2132.                  /NO_COPY, /SET
  2133.  
  2134.    if not(KEYWORD_SET(directDraw)) then begin
  2135.       WSET, sMainState.sProfState.profPix
  2136.       PLOT, profData, yData, TICKLEN=(1), XSTYLE=1, YSTYLE=5, $
  2137.          XRANGE=[lTh, hTh], YRANGE=[0, maxY], XMARGIN=[1,1], YMARGIN=[2,1], $
  2138.          /NODATA, COLOR=axisColor, CHARSIZE=0.5
  2139.       PLOTS, [lTh,lTh], [0,maxY], /DATA, T3D=0, COLOR=axisColor
  2140.       PLOTS, [hTh,hTh], [0,maxY], /DATA, T3D=0, COLOR=axisColor
  2141.       PLOTS, [lTh,hTh], [0,0], /DATA, T3D=0, COLOR=markColor1, THICK=2
  2142.       PLOTS, [lTh,hTh], [maxY,maxY], /DATA, T3D=0, COLOR=markColor2, THICK=2
  2143.    endif
  2144.    WSET, sMainState.sProfState.profWin
  2145.    DEVICE, COPY=[0, 0, 192, sMainState.sProfState.profWinY, 0, 0, $
  2146.                  sMainState.sProfState.profPix]
  2147.  
  2148.    PLOT, TEMPORARY(profData), TEMPORARY(yData), TICKLEN=(1), XMARGIN=[1,1], $
  2149.       YMARGIN=[2,1], /NOERASE, COLOR=lineColor, XSTYLE=5, YSTYLE=5, $
  2150.       XRANGE=[lTh, hTh], YRANGE=[0, maxY], CHARSIZE=0.5, /DATA, T3D=0
  2151.    EMPTY
  2152.  
  2153.    !P = TEMPORARY(saveP)
  2154.    !X = TEMPORARY(saveX)
  2155.    !Y = TEMPORARY(saveY)
  2156.    !Z = TEMPORARY(saveZ)
  2157.  
  2158.    WSET, sMainState.mainWin
  2159. end
  2160. ;******************************************************************************
  2161.  
  2162.  
  2163. ;******************************************************************************
  2164. ; Function to return the transparent value given a threshold percent.
  2165. ; Compensate for the differential shading bands using planeDir.
  2166. function Viz3D_TranspValu, sMainState, planeDir
  2167.    HANDLE_VALUE, sMainState.sThreshState.hLowThresh, lowThresh, /NO_COPY
  2168.    HANDLE_VALUE, sMainState.sThreshState.hHighThresh, highThresh, /NO_COPY
  2169.    HANDLE_VALUE, sMainState.sThreshState.hTransVal, transVal, /NO_COPY
  2170.    lTh = lowThresh(sMainState.curData)
  2171.    hTh = highThresh(sMainState.curData)
  2172.    vTp = transVal(sMainState.curData)
  2173.    HANDLE_VALUE, sMainState.sThreshState.hLowThresh, lowThresh, $
  2174.                  /NO_COPY, /SET
  2175.    HANDLE_VALUE, sMainState.sThreshState.hHighThresh, highThresh, $
  2176.                  /NO_COPY, /SET
  2177.    HANDLE_VALUE, sMainState.sThreshState.hTransVal, transVal, /NO_COPY, /SET
  2178.    transVal = (vTp - lTh) / (hTh - lTh)
  2179.    transVal = (transVal * FLOAT(sMainState.sColorState.nColor-1)) > 0.0
  2180.  
  2181.    return, ROUND(transVal) + (planeDir * sMainState.sColorState.nColor)
  2182. end
  2183. ;******************************************************************************
  2184.  
  2185.  
  2186. ;******************************************************************************
  2187. ; Add a new graphic to the display list.
  2188. function Viz3D_Add_Graphic, sMainState, graphic, NO_COPY=noCopy
  2189.  
  2190.    gType = TAG_NAMES(graphic, /STRUCTURE_NAME)
  2191.    case gType of
  2192.       'VIZ3D_ORTHO_PLANE': begin
  2193.          gName = 'Slice: Orthogonal, '
  2194.          case graphic.orthoDir of
  2195.             1: begin
  2196.                gName = TEMPORARY(gName) + 'X, ' + $
  2197.                STRTRIM(STRING(ROUND(graphic.orthoPos * $
  2198.                   sMainState.sViewState.xMax)), 2)
  2199.             end
  2200.             2: begin
  2201.                gName = TEMPORARY(gName) + 'Y, ' + $
  2202.                STRTRIM(STRING(ROUND(graphic.orthoPos * $
  2203.                   sMainState.sViewState.yMax)), 2)
  2204.             end
  2205.             3: begin
  2206.                gName = TEMPORARY(gName) + 'Z, ' + $
  2207.                STRTRIM(STRING(ROUND(graphic.orthoPos * $
  2208.                   sMainState.sViewState.zMax)), 2)
  2209.             end
  2210.          endcase
  2211.       end
  2212.       'VIZ3D_OBLIQ_PLANE': begin
  2213.          gName = 'Slice: Oblique'
  2214.       end
  2215.       'VIZ3D_BLOCK': begin
  2216.          gName = 'Block: '
  2217.          case graphic.blockMode of
  2218.             0: gName = TEMPORARY(gName) + 'Subract, ('
  2219.             1: gName = TEMPORARY(gName) + 'Add, ('
  2220.          endcase
  2221.          gName = TEMPORARY(gName) + STRTRIM(STRING(graphic.c1(0)), 2) + ','
  2222.          gName = TEMPORARY(gName) + STRTRIM(STRING(graphic.c1(1)), 2) + ','
  2223.          gName = TEMPORARY(gName) + STRTRIM(STRING(graphic.c1(2)), 2) + '), ('
  2224.          gName = TEMPORARY(gName) + STRTRIM(STRING(graphic.c2(0)), 2) + ','
  2225.          gName = TEMPORARY(gName) + STRTRIM(STRING(graphic.c2(1)), 2) + ','
  2226.          gName = TEMPORARY(gName) + STRTRIM(STRING(graphic.c2(2)), 2) + ')'
  2227.       end
  2228.       'VIZ3D_SURF': begin
  2229.          gName = 'Surface: '
  2230.          case graphic.surfSide of
  2231.             0: gName = TEMPORARY(gName) + 'Low, '
  2232.             1: gName = TEMPORARY(gName) + 'High, '
  2233.          endcase
  2234.          gName = TEMPORARY(gName) + STRTRIM(STRING(graphic.surfThresh), 2)
  2235.       end
  2236.       'VIZ3D_PROJ': begin
  2237.          gName = 'Projection: '
  2238.          case graphic.projType of
  2239.             0: gName = TEMPORARY(gName) + 'Max, '
  2240.             1: gName = TEMPORARY(gName) + 'Avg, '
  2241.          endcase
  2242.          case graphic.projReso of
  2243.             0: gName = TEMPORARY(gName) + 'Low'
  2244.             1: gName = TEMPORARY(gName) + 'Med'
  2245.             2: gName = TEMPORARY(gName) + 'High'
  2246.          endcase
  2247.       end
  2248.    endcase
  2249.  
  2250.    wDeleteBttn = WIDGET_BUTTON(sMainState.wDeleteMenu, VALUE=gName, $
  2251.                                UVALUE='wDeleteBttn')
  2252.  
  2253.    return, HANDLE_CREATE(sMainState.hDisplayList, VALUE=graphic, $
  2254.                          NO_COPY=KEYWORD_SET(noCopy))
  2255.  
  2256. end
  2257. ;******************************************************************************
  2258.  
  2259.  
  2260. ;******************************************************************************
  2261. ; Procedure to draw the data on an orthogonal slicing plane.
  2262. pro Viz3D_OrthoPlaneDraw, sMainState, SKIP_ADD=skipAdd, SKIP_DRAW=skipDraw
  2263.  
  2264.    WIDGET_CONTROL, sMainState.wStatText, $
  2265.       SET_VALUE=('Drawing orthogonal plane ...')
  2266.  
  2267.    sliceDir = sMainState.sSliceState.orthoDir
  2268.    slicePos = sMainState.sSliceState.orthoPos
  2269.  
  2270.    ; Check out the data without making a copy.
  2271.    data3D = Viz3D_GetData(sMainState)
  2272.  
  2273.    case sliceDir of
  2274.       1: begin ; X
  2275.          pPos = ROUND(slicePos * sMainState.sViewState.xMax)
  2276.          dataPlane = REFORM(data3D(pPos, *, *))
  2277.          x = REPLICATE(slicePos, 4)
  2278.          y = [0.0,1.0,1.0,0.0]
  2279.          z = [0.0,0.0,1.0,1.0]
  2280.          pDim1 = sMainState.sViewState.yMax
  2281.          pDim2 = sMainState.sViewState.zMax
  2282.       end
  2283.       2: begin ; Y
  2284.          pPos = ROUND(slicePos * sMainState.sViewState.yMax)
  2285.          dataPlane = REFORM(data3D(*, pPos, *))
  2286.          x = [0.0,1.0,1.0,0.0]
  2287.          y = REPLICATE(slicePos, 4)
  2288.          z = [0.0,0.0,1.0,1.0]
  2289.          pDim1 = sMainState.sViewState.xMax
  2290.          pDim2 = sMainState.sViewState.zMax
  2291.       end
  2292.       3: begin ; Z
  2293.          pPos = ROUND(slicePos * sMainState.sViewState.zMax)
  2294.          dataPlane = REFORM(data3D(*, *, pPos))
  2295.          x = [0.0,1.0,1.0,0.0]
  2296.          y = [0.0,0.0,1.0,1.0]
  2297.          z = REPLICATE(slicePos, 4)
  2298.          pDim1 = sMainState.sViewState.xMax
  2299.          pDim2 = sMainState.sViewState.yMax
  2300.       end
  2301.    endcase
  2302.  
  2303.    ; Check the data back in again.
  2304.    Viz3D_PutData, data3D, sMainState
  2305.  
  2306.    ; Extract the data on the orthogonal plane.
  2307.    dataPlane = Viz3D_ScaleData(Temporary(dataPlane), sMainState)
  2308.  
  2309.    ; Scale the data to the current threshold.
  2310.    dataPlane = BYTSCL(TEMPORARY(dataPlane), MIN=0B, MAX=255B, $
  2311.                       TOP=sMainState.sColorState.nColor-1)
  2312.  
  2313.    ; Shift the data into the appropriate differential shading
  2314.    ; portion of the color table.
  2315.    dataPlane = TEMPORARY(dataPlane) + $
  2316.       BYTE((sliceDir-1) * sMainState.sColorState.nColor)
  2317.  
  2318.    ; Draw the slice in the Z buffer.
  2319.  
  2320.    SET_PLOT, 'Z'
  2321.  
  2322.    if (sMainState.sSliceState.drawMode) then begin ; Expose mode
  2323.       tempImage = TVRD()
  2324.       tempDepth = TVRD(/WORDS, CHANNEL=1)
  2325.       ERASE
  2326.       POLYFILL, x, y, z, PATTERN=dataPlane, /T3D, /NORMAL, $
  2327.          IMAGE_INTERP=sMainState.interpMode, $
  2328.          TRANSPARENT=Viz3D_TranspValu(sMainState, sliceDir-1), $
  2329.          IMAGE_COORD=[[0,0], [pDim1,0], [pDim1,pDim2], [0,pDim2]]
  2330.       planeDepth = TVRD(/WORDS, CHANNEL=1)
  2331.       planeIndex = WHERE(TEMPORARY(planeDepth) gt (-32765))
  2332.       tempDepth(TEMPORARY(planeIndex)) = (-32765)
  2333.       planeDepth = 0
  2334.       TV, TEMPORARY(tempDepth), /WORDS, CHANNEL=1
  2335.       TV, TEMPORARY(tempImage)
  2336.    endif
  2337.  
  2338.    POLYFILL, x, y, z, PATTERN=dataPlane, /T3D, /NORMAL, $
  2339.       IMAGE_INTERP=sMainState.interpMode, $
  2340.       TRANSPARENT=Viz3D_TranspValu(sMainState, sliceDir-1), $
  2341.       IMAGE_COORD=[[0,0], [pDim1,0], [pDim1,pDim2], [0,pDim2]]
  2342.  
  2343.    SET_PLOT, sMainState.screenDevice
  2344.  
  2345.    ; Update the big view window.
  2346.    if (NOT(KEYWORD_SET(skipDraw))) then $
  2347.       Viz3D_DrawData, sMainState
  2348.  
  2349.    ; Add orthogonal plane to sMainState.hDisplayList
  2350.    if (NOT(KEYWORD_SET(skipAdd))) then begin
  2351.       HANDLE_VALUE, sMainState.sThreshState.hLowThresh, lowThresh, $
  2352.          /NO_COPY
  2353.       HANDLE_VALUE, sMainState.sThreshState.hHighThresh, highThresh, $
  2354.          /NO_COPY
  2355.       HANDLE_VALUE, sMainState.sThreshState.hTransVal, transVal, $
  2356.          /NO_COPY
  2357.       lTh = lowThresh(sMainState.curData)
  2358.       hTh = highThresh(sMainState.curData)
  2359.       vTp = transVal(sMainState.curData)
  2360.       HANDLE_VALUE, sMainState.sThreshState.hLowThresh, lowThresh, $
  2361.          /NO_COPY, /SET
  2362.       HANDLE_VALUE, sMainState.sThreshState.hHighThresh, highThresh, $
  2363.          /NO_COPY, /SET
  2364.       HANDLE_VALUE, sMainState.sThreshState.hTransVal, transVal, $
  2365.          /NO_COPY, /SET
  2366.       graphic = {VIZ3D_ORTHO_PLANE, curData:sMainState.curData, $
  2367.                  orthoDir:sMainState.sSliceState.orthoDir, $
  2368.                  orthoPos:sMainState.sSliceState.orthoPos, $
  2369.                  drawMode:sMainState.sSliceState.drawMode, $
  2370.                  lowThresh:lTh, highThresh:hTh, transVal:vTp}
  2371.       h = Viz3D_Add_Graphic(sMainState, graphic, /NO_COPY)
  2372.    endif
  2373.  
  2374.    WIDGET_CONTROL, sMainState.wStatText, SET_VALUE=('')
  2375.  
  2376. end
  2377. ;******************************************************************************
  2378.  
  2379.  
  2380. ;******************************************************************************
  2381. ; Procedure to draw the data on an oblique slicing plane.
  2382. pro Viz3D_ObliqPlaneDraw, sMainState, vertPlane, vert3D, SKIP_ADD=skipAdd, $
  2383.        SKIP_DRAW=skipDraw
  2384.  
  2385.    WIDGET_CONTROL, sMainState.wStatText, $
  2386.       SET_VALUE=('Drawing oblique plane ...')
  2387.  
  2388.    sliceNormal = sMainState.sSliceState.obliqNormal
  2389.    sliceCenter = sMainState.sSliceState.obliqCenter
  2390.  
  2391.    ; Compute the maximum necessary slicing plane image dimension.
  2392.    maxLen = LONG(SQRT(sMainState.sViewState.xMax^2 + $
  2393.                       sMainState.sViewState.yMax^2 + $
  2394.                       sMainState.sViewState.zMax^2))
  2395.  
  2396.    ; Compute the amount necessary to shift the slicing plane to the center.
  2397.    maxXvert = MAX(vertPlane(0,*), MIN=minXvert)
  2398.    maxYvert = MAX(vertPlane(1,*), MIN=minYvert)
  2399.    shiftX = (maxXvert + minXvert) / 2.0
  2400.    shiftY = (maxYvert + minYvert) / 2.0
  2401.  
  2402.    maxP = SQRT(3.0) ; Slicing rectangle interpolation points
  2403.                     ; range between 0 and SQRT(3) in X and Y
  2404.                     ; (before shift and transformation).
  2405.  
  2406.    ; Compute the shifted interpolation points on the plane.
  2407.    ; (Normalized coordinates, with no rotation or translation).
  2408.    planePts = FLTARR(3, maxLen^2, /NOZERO)
  2409.    sF = FLOAT(maxLen-1L)
  2410.    planePts(0, *) = shiftX + $
  2411.       ((((FINDGEN(maxLen) # REPLICATE(1.0, maxLen)) / sF) - 0.5) * maxP)
  2412.    planePts(1, *) = shiftY + $
  2413.       ((((REPLICATE(1.0, maxLen) # FINDGEN(maxLen)) / sF) - 0.5) * maxP)
  2414.    planePts(2, *) = 0.0
  2415.  
  2416.    ; Scale the surface normal vector.
  2417.    zDim = sMainState.sViewState.zMax * sMainState.sViewState.zScale
  2418.    maxDim = sMainState.sViewState.xMax > sMainState.sViewState.yMax > zDim
  2419.    sliceNormU = sliceNormal
  2420.    sliceNormU(0) = sliceNormal(0) * sMainState.sViewState.xMax / maxDim
  2421.    sliceNormU(1) = sliceNormal(1) * sMainState.sViewState.yMax / maxDim
  2422.    sliceNormU(2) = sliceNormal(2) * zDim / maxDim
  2423.  
  2424.    ; Compute the rotations and transformation matrix.
  2425.  
  2426.    if ((sliceNormU(0) eq 0.0) and (sliceNormU(1) eq 0.0)) then angZ = 0.0 $
  2427.    else angZ = ATAN(sliceNormU(1), sliceNormU(0))
  2428.  
  2429.    pDistance = SQRT(sliceNormU(0)^2 + sliceNormU(1)^2)
  2430.    if ((pDistance eq 0.0) and (sliceNormU(2) eq 0.0)) then angY = 0.0 $
  2431.    else angY = ATAN(sliceNormU(2), pDistance)
  2432.  
  2433.    sZ = SIN(angZ)
  2434.    cZ = COS(angZ)
  2435.    sY = SIN((!PI/2.0)-angY)
  2436.    cY = COS((!PI/2.0)-angY)
  2437.  
  2438.    ident4 = FLTARR(4, 4)
  2439.    ident4([0,5,10,15]) = 1.0
  2440.  
  2441.    vTrans = ident4
  2442.    ; Y rotation.
  2443.    m4X4 = ident4
  2444.    m4x4(0,0) = cY
  2445.    m4x4(0,2) = (-sY)
  2446.    m4x4(2,0) = sY
  2447.    m4x4(2,2) = cY
  2448.    vTrans = TEMPORARY(vTrans) # m4X4
  2449.    ; Z rotation.
  2450.    m4X4 = ident4
  2451.    m4x4(0,0) = cZ
  2452.    m4x4(0,1) = sZ
  2453.    m4x4(1,0) = (-sZ)
  2454.    m4x4(1,1) = cZ
  2455.    vTrans = TEMPORARY(vTrans) # m4X4
  2456.    ; Translation to the slice center.
  2457.    m4X4 = ident4
  2458.    m4X4([3,7,11]) = (+sliceCenter)
  2459.    vTrans = TEMPORARY(vTrans) # m4X4
  2460.  
  2461.    ; Transform the plane points.
  2462.    planePts = VERT_T3D(planePts, MATRIX=vTrans, /NO_COPY)
  2463.    planePts(0, *) = planePts(0, *) * Float(sMainState.sViewState.xMax)
  2464.    planePts(1, *) = planePts(1, *) * Float(sMainState.sViewState.yMax)
  2465.    planePts(2, *) = planePts(2, *) * Float(sMainState.sViewState.zMax)
  2466.  
  2467.    ; Check out the data without making a copy.
  2468.    data3D = Viz3D_GetData(sMainState)
  2469.  
  2470.    ; Interpolate the data on the oblique plane using the plane points,
  2471.    dataPlane = $
  2472.       Interpolate(data3D, planePts(0,*), planePts(1,*), planePts(2,*))
  2473.  
  2474.    ; Check the data back in.
  2475.    Viz3D_PutData, data3D, sMainState
  2476.  
  2477.    ; Free the memory used by planePts.
  2478.    planePts = 0
  2479.  
  2480.    ; Scale the oblique plane data using the current thresholds.
  2481.    dataPlane = Viz3D_ScaleData(Temporary(dataPlane), sMainState)
  2482.  
  2483.    ; Scale the oblique plane data into the appropriate part of the color table
  2484.    ; (for differential shading).
  2485.    dataPlane = BYTSCL(TEMPORARY(dataPlane), MIN=0B, MAX=255B, $
  2486.                       TOP=sMainState.sColorState.nColor-1)
  2487.    maxDir = MAX(ABS(sliceNormU), maxInd)
  2488.    dataPlane = TEMPORARY(dataPlane) + $
  2489.       BYTE(maxInd * sMainState.sColorState.nColor)
  2490.  
  2491.    ; Reform dataPlane from a one dimensional array of (maxLen^2) elements
  2492.    ; to a 2D array with dimensions (maxLen, maxLen).
  2493.    dataPlane = REFORM(TEMPORARY(dataPlane), maxLen, maxLen)
  2494.  
  2495.    ; USE the Z buffer.
  2496.  
  2497.    SET_PLOT, 'Z'
  2498.  
  2499.    ; Compute the image coordinates corresponding to the planar cube/plane
  2500.    ; intersection points.
  2501.  
  2502.    s_vertPlane = vertPlane(0:1, *)
  2503.    s_vertPlane(0,*) = (s_vertPlane(0,*) / maxP) + 0.5 - (shiftX / maxP)
  2504.    s_vertPlane(1,*) = (s_vertPlane(1,*) / maxP) + 0.5 - (shiftY / maxP)
  2505.    s_vertPlane = TEMPORARY(s_vertPlane) * sF
  2506.  
  2507.    if (sMainState.sSliceState.drawMode) then begin ; Expose mode
  2508.       tempImage = TVRD()
  2509.       tempDepth = TVRD(/WORDS, CHANNEL=1)
  2510.       ERASE
  2511.       POLYFILL, vert3D, PATTERN=dataPlane, /T3D, /NORMAL, $
  2512.          IMAGE_INTERP=sMainState.interpMode, $
  2513.          TRANSPARENT=Viz3D_TranspValu(sMainState, maxInd), $
  2514.          IMAGE_COORD=s_vertPlane
  2515.       planeDepth = TVRD(/WORDS, CHANNEL=1)
  2516.       planeIndex = WHERE(planeDepth ge (-32765))
  2517.       if (planeIndex(0) ge 0L) then begin
  2518.          tempDepth(planeIndex) = planeDepth(planeIndex)
  2519.       endif
  2520.       planeDepth = 0
  2521.       TV, TEMPORARY(tempDepth), /WORDS, CHANNEL=1
  2522.       TV, TEMPORARY(tempImage)
  2523.    endif
  2524.  
  2525.    ; Draw the data on the oblique plane.
  2526.    POLYFILL, vert3D, PATTERN=dataPlane, /T3D, /NORMAL, $
  2527.       IMAGE_INTERP=sMainState.interpMode, $
  2528.       TRANSPARENT=Viz3D_TranspValu(sMainState, maxInd), $
  2529.       IMAGE_COORD=s_vertPlane
  2530.  
  2531.    SET_PLOT, sMainState.screenDevice
  2532.  
  2533.    ; Update the big view window.
  2534.    if (NOT(KEYWORD_SET(skipDraw))) then $
  2535.       Viz3D_DrawData, sMainState
  2536.  
  2537.    ; Add oblique plane to sMainState.hDisplayList
  2538.    if (NOT(KEYWORD_SET(skipAdd))) then begin
  2539.       HANDLE_VALUE, sMainState.sThreshState.hLowThresh, lowThresh, $
  2540.          /NO_COPY
  2541.       HANDLE_VALUE, sMainState.sThreshState.hHighThresh, highThresh, $
  2542.          /NO_COPY
  2543.       HANDLE_VALUE, sMainState.sThreshState.hTransVal, transVal, $
  2544.          /NO_COPY
  2545.       lTh = lowThresh(sMainState.curData)
  2546.       hTh = highThresh(sMainState.curData)
  2547.       vTp = transVal(sMainState.curData)
  2548.       HANDLE_VALUE, sMainState.sThreshState.hLowThresh, lowThresh, $
  2549.          /NO_COPY, /SET
  2550.       HANDLE_VALUE, sMainState.sThreshState.hHighThresh, highThresh, $
  2551.          /NO_COPY, /SET
  2552.       HANDLE_VALUE, sMainState.sThreshState.hTransVal, transVal, $
  2553.          /NO_COPY, /SET
  2554.       graphic = {VIZ3D_OBLIQ_PLANE, curData:sMainState.curData, $
  2555.                  hVertPlane:0L, hVert3D:0L, $
  2556.                  drawMode:sMainState.sSliceState.drawMode, $
  2557.                  obliqNormal:sMainState.sSliceState.obliqNormal, $
  2558.                  obliqCenter:sMainState.sSliceState.obliqCenter, $
  2559.                  lowThresh:lTh, highThresh:hTh, transVal:vTp}
  2560.       h = Viz3D_Add_Graphic(sMainState, graphic, /NO_COPY)
  2561.       HANDLE_VALUE, h, graphic, /NO_COPY
  2562.       graphic.hVertPlane = HANDLE_CREATE(h, VALUE=vertPlane, /NO_COPY)
  2563.       graphic.hVert3D = HANDLE_CREATE(h, VALUE=vert3D, /NO_COPY)
  2564.       HANDLE_VALUE, h, graphic, /NO_COPY, /SET
  2565.    endif
  2566.  
  2567.    WIDGET_CONTROL, sMainState.wStatText, SET_VALUE=('')
  2568. end
  2569. ;******************************************************************************
  2570.  
  2571.  
  2572. ;******************************************************************************
  2573. ; Procedure to draw the data on a block.
  2574. pro Viz3D_BlockDraw, sMainState, SKIP_ADD=skipAdd, SKIP_DRAW=skipDraw
  2575.  
  2576.    WIDGET_CONTROL, sMainState.wStatText, $
  2577.       SET_VALUE=('Drawing block ...')
  2578.  
  2579.    x1 = FLOAT(sMainState.sBlockState.c1(0) < sMainState.sBlockState.c2(0))
  2580.    x2 = FLOAT(sMainState.sBlockState.c1(0) > sMainState.sBlockState.c2(0))
  2581.    y1 = FLOAT(sMainState.sBlockState.c1(1) < sMainState.sBlockState.c2(1))
  2582.    y2 = FLOAT(sMainState.sBlockState.c1(1) > sMainState.sBlockState.c2(1))
  2583.    z1 = FLOAT(sMainState.sBlockState.c1(2) < sMainState.sBlockState.c2(2))
  2584.    z2 = FLOAT(sMainState.sBlockState.c1(2) > sMainState.sBlockState.c2(2))
  2585.  
  2586.    ; Return if any block dimension is zero.
  2587.    if (((x1 eq x2) or (y1 eq y2)) or (z1 eq z2)) then return
  2588.  
  2589.    ; Check out the data without making a copy.
  2590.    data3D = Viz3D_GetData(sMainState)
  2591.  
  2592.    SET_PLOT, 'Z'
  2593.  
  2594.    if (sMainState.sBlockState.blockMode) then begin ; Add mode.
  2595.       dim1 = (x2 - x1)
  2596.       dim2 = (y2 - y1)
  2597.       faceDir = 2
  2598.       subImg = Viz3D_ScaleData(REFORM(data3D(x1:x2, y1:y2, z1)), sMainState)
  2599.       subImg = BYTSCL(TEMPORARY(subImg), MIN=0B, MAX=255B, $
  2600.                       TOP=sMainState.sColorState.nColor-1)
  2601.       subImg = TEMPORARY(subImg) + $
  2602.                   BYTE(faceDir * sMainState.sColorState.nColor)
  2603.       POLYFILL, [x1,x2,x2,x1], [y1,y1,y2,y2], [z1,z1,z1,z1], PATTERN=subImg, $
  2604.          /T3D, /DATA, IMAGE_INTERP=sMainState.interpMode, $
  2605.          TRANSPARENT=Viz3D_TranspValu(sMainState, faceDir), $
  2606.          IMAGE_COORD=[[0,0],[dim1,0],[dim1,dim2],[0,dim2]]
  2607.       subImg = Viz3D_ScaleData(REFORM(data3D(x1:x2, y1:y2, z2)), sMainState)
  2608.       subImg = BYTSCL(TEMPORARY(subImg), MIN=0B, MAX=255B, $
  2609.                       TOP=sMainState.sColorState.nColor-1)
  2610.       subImg = TEMPORARY(subImg) + $
  2611.                   BYTE(faceDir * sMainState.sColorState.nColor)
  2612.       POLYFILL, [x1,x2,x2,x1], [y1,y1,y2,y2], [z2,z2,z2,z2], PATTERN=subImg, $
  2613.          /T3D, /DATA, IMAGE_INTERP=sMainState.interpMode, $
  2614.          TRANSPARENT=Viz3D_TranspValu(sMainState, faceDir), $
  2615.          IMAGE_COORD=[[0,0],[dim1,0],[dim1,dim2],[0,dim2]]
  2616.  
  2617.       dim1 = (x2 - x1)
  2618.       dim2 = (z2 - z1)
  2619.       faceDir = 1
  2620.       subImg = Viz3D_ScaleData(REFORM(data3D(x1:x2, y1, z1:z2)), sMainState)
  2621.       subImg = BYTSCL(TEMPORARY(subImg), MIN=0B, MAX=255B, $
  2622.                       TOP=sMainState.sColorState.nColor-1)
  2623.       subImg = TEMPORARY(subImg) + $
  2624.                   BYTE(faceDir * sMainState.sColorState.nColor)
  2625.       POLYFILL, [x1,x2,x2,x1], [y1,y1,y1,y1], [z1,z1,z2,z2], PATTERN=subImg, $
  2626.          /T3D, /DATA, IMAGE_INTERP=sMainState.interpMode, $
  2627.          TRANSPARENT=Viz3D_TranspValu(sMainState, faceDir), $
  2628.          IMAGE_COORD=[[0,0],[dim1,0],[dim1,dim2],[0,dim2]]
  2629.       subImg = Viz3D_ScaleData(REFORM(data3D(x1:x2, y2, z1:z2)), sMainState)
  2630.       subImg = BYTSCL(TEMPORARY(subImg), MIN=0B, MAX=255B, $
  2631.                       TOP=sMainState.sColorState.nColor-1)
  2632.       subImg = TEMPORARY(subImg) + $
  2633.                   BYTE(faceDir * sMainState.sColorState.nColor)
  2634.       POLYFILL, [x1,x2,x2,x1], [y2,y2,y2,y2], [z1,z1,z2,z2], PATTERN=subImg, $
  2635.          /T3D, /DATA, IMAGE_INTERP=sMainState.interpMode, $
  2636.          TRANSPARENT=Viz3D_TranspValu(sMainState, faceDir), $
  2637.          IMAGE_COORD=[[0,0],[dim1,0],[dim1,dim2],[0,dim2]]
  2638.  
  2639.       dim1 = (y2 - y1)
  2640.       dim2 = (z2 - z1)
  2641.       faceDir = 0
  2642.       subImg = Viz3D_ScaleData(REFORM(data3D(x1, y1:y2, z1:z2)), sMainState)
  2643.       subImg = BYTSCL(TEMPORARY(subImg), MIN=0B, MAX=255B, $
  2644.                       TOP=sMainState.sColorState.nColor-1)
  2645.       subImg = TEMPORARY(subImg) + $
  2646.                   BYTE(faceDir * sMainState.sColorState.nColor)
  2647.       POLYFILL, [x1,x1,x1,x1], [y1,y2,y2,y1], [z1,z1,z2,z2], PATTERN=subImg, $
  2648.          /T3D, /DATA, IMAGE_INTERP=sMainState.interpMode, $
  2649.          TRANSPARENT=Viz3D_TranspValu(sMainState, faceDir), $
  2650.          IMAGE_COORD=[[0,0],[dim1,0],[dim1,dim2],[0,dim2]]
  2651.       subImg = Viz3D_ScaleData(REFORM(data3D(x2, y1:y2, z1:z2)), sMainState)
  2652.       subImg = BYTSCL(TEMPORARY(subImg), MIN=0B, MAX=255B, $
  2653.                       TOP=sMainState.sColorState.nColor-1)
  2654.       subImg = TEMPORARY(subImg) + $
  2655.                   BYTE(faceDir * sMainState.sColorState.nColor)
  2656.       POLYFILL, [x2,x2,x2,x2], [y1,y2,y2,y1], [z1,z1,z2,z2], PATTERN=subImg, $
  2657.          /T3D, /DATA, IMAGE_INTERP=sMainState.interpMode, $
  2658.          TRANSPARENT=Viz3D_TranspValu(sMainState, faceDir), $
  2659.          IMAGE_COORD=[[0,0],[dim1,0],[dim1,dim2],[0,dim2]]
  2660.  
  2661.  
  2662.    endif else begin ; Subtract mode.
  2663.       dims = FLOAT([sMainState.sViewState.xMax, sMainState.sViewState.yMax, $
  2664.                     sMainState.sViewState.zMax])
  2665.       dims = [[dims], [dims]]
  2666.  
  2667.       imageBuffer1 = TVRD()
  2668.       depthBuffer1 = TVRD(CHANNEL=1, /WORDS)
  2669.       POLYFILL, [x1,x2,x2,x1], [y1,y1,y2,y2], [z1,z1,z1,z1], /T3D, /DATA
  2670.       POLYFILL, [x1,x2,x2,x1], [y1,y1,y2,y2], [z2,z2,z2,z2], /T3D, /DATA
  2671.       POLYFILL, [x1,x2,x2,x1], [y1,y1,y1,y1], [z1,z1,z2,z2], /T3D, /DATA
  2672.       POLYFILL, [x1,x2,x2,x1], [y2,y2,y2,y2], [z1,z1,z2,z2], /T3D, /DATA
  2673.       POLYFILL, [x1,x1,x1,x1], [y1,y2,y2,y1], [z1,z1,z2,z2], /T3D, /DATA
  2674.       POLYFILL, [x2,x2,x2,x2], [y1,y2,y2,y1], [z1,z1,z2,z2], /T3D, /DATA
  2675.       depthMask1 = (TVRD(CHANNEL=1, /WORDS) gt depthBuffer1)
  2676.  
  2677.       ERASE
  2678.  
  2679.       norm = [[x1,y1,z1], [x1,y1,z1-1.0]] / dims
  2680.       norm = VERT_T3D(norm, /NO_COPY)
  2681.       if ((norm(2,1)-norm(2,0)) lt 0.0) then begin
  2682.          dim1 = (x2 - x1)
  2683.          dim2 = (y2 - y1)
  2684.          faceDir = 2
  2685.          subImg = $
  2686.             Viz3D_ScaleData(REFORM(data3D(x1:x2, y1:y2, z1)), sMainState)
  2687.          subImg = BYTSCL(TEMPORARY(subImg), MIN=0B, MAX=255B, $
  2688.                          TOP=sMainState.sColorState.nColor-1)
  2689.          subImg = TEMPORARY(subImg) + $
  2690.                      BYTE(faceDir * sMainState.sColorState.nColor)
  2691.          POLYFILL, [x1,x2,x2,x1], [y1,y1,y2,y2], [z1,z1,z1,z1], $
  2692.             PATTERN=subImg, /T3D, /DATA, IMAGE_INTERP=sMainState.interpMode, $
  2693.             TRANSPARENT=Viz3D_TranspValu(sMainState, faceDir), $
  2694.             IMAGE_COORD=[[0,0],[dim1,0],[dim1,dim2],[0,dim2]]
  2695.       endif
  2696.  
  2697.       norm = [[x1,y1,z1], [x1,y1-1.0,z1]] / dims
  2698.       norm = VERT_T3D(norm, /NO_COPY)
  2699.       if ((norm(2,1)-norm(2,0)) lt 0.0) then begin
  2700.          dim1 = (x2 - x1)
  2701.          dim2 = (z2 - z1)
  2702.          faceDir = 1
  2703.          subImg = $
  2704.             Viz3D_ScaleData(REFORM(data3D(x1:x2, y1, z1:z2)), sMainState)
  2705.          subImg = BYTSCL(TEMPORARY(subImg), MIN=0B, MAX=255B, $
  2706.                          TOP=sMainState.sColorState.nColor-1)
  2707.          subImg = TEMPORARY(subImg) + $
  2708.                      BYTE(faceDir * sMainState.sColorState.nColor)
  2709.          POLYFILL, [x1,x2,x2,x1], [y1,y1,y1,y1], [z1,z1,z2,z2], $
  2710.             PATTERN=subImg, /T3D, /DATA, IMAGE_INTERP=sMainState.interpMode, $
  2711.             TRANSPARENT=Viz3D_TranspValu(sMainState, faceDir), $
  2712.             IMAGE_COORD=[[0,0],[dim1,0],[dim1,dim2],[0,dim2]]
  2713.       endif
  2714.  
  2715.       norm = [[x1,y1,z1], [x1-1.0,y1,z1]] / dims
  2716.       norm = VERT_T3D(norm, /NO_COPY)
  2717.       if ((norm(2,1)-norm(2,0)) lt 0.0) then begin
  2718.          dim1 = (y2 - y1)
  2719.          dim2 = (z2 - z1)
  2720.          faceDir = 0
  2721.          subImg = $
  2722.             Viz3D_ScaleData(REFORM(data3D(x1, y1:y2, z1:z2)), sMainState)
  2723.          subImg = BYTSCL(TEMPORARY(subImg), MIN=0B, MAX=255B, $
  2724.                          TOP=sMainState.sColorState.nColor-1)
  2725.          subImg = TEMPORARY(subImg) + $
  2726.                      BYTE(faceDir * sMainState.sColorState.nColor)
  2727.          POLYFILL, [x1,x1,x1,x1], [y1,y2,y2,y1], [z1,z1,z2,z2], $
  2728.             PATTERN=subImg, /T3D, /DATA, IMAGE_INTERP=sMainState.interpMode, $
  2729.             TRANSPARENT=Viz3D_TranspValu(sMainState, faceDir), $
  2730.             IMAGE_COORD=[[0,0],[dim1,0],[dim1,dim2],[0,dim2]]
  2731.       endif
  2732.  
  2733.       norm = [[x2,y2,z2], [x2,y2,z2+1.0]] / dims
  2734.       norm = VERT_T3D(norm, /NO_COPY)
  2735.       if ((norm(2,1)-norm(2,0)) lt 0.0) then begin
  2736.          dim1 = (x2 - x1)
  2737.          dim2 = (y2 - y1)
  2738.          faceDir = 2
  2739.          subImg = $
  2740.             Viz3D_ScaleData(REFORM(data3D(x1:x2, y1:y2, z2)), sMainState)
  2741.          subImg = BYTSCL(TEMPORARY(subImg), MIN=0B, MAX=255B, $
  2742.                          TOP=sMainState.sColorState.nColor-1)
  2743.          subImg = TEMPORARY(subImg) + $
  2744.                      BYTE(faceDir * sMainState.sColorState.nColor)
  2745.          POLYFILL, [x1,x2,x2,x1], [y1,y1,y2,y2], [z2,z2,z2,z2], $
  2746.             PATTERN=subImg, /T3D, /DATA, IMAGE_INTERP=sMainState.interpMode, $
  2747.             TRANSPARENT=Viz3D_TranspValu(sMainState, faceDir), $
  2748.             IMAGE_COORD=[[0,0],[dim1,0],[dim1,dim2],[0,dim2]]
  2749.       endif
  2750.  
  2751.       norm = [[x2,y2,z2], [x2,y2+1.0,z2]] / dims
  2752.       norm = VERT_T3D(norm, /NO_COPY)
  2753.       if ((norm(2,1)-norm(2,0)) lt 0.0) then begin
  2754.          dim1 = (x2 - x1)
  2755.          dim2 = (z2 - z1)
  2756.          faceDir = 1
  2757.          subImg = $
  2758.             Viz3D_ScaleData(REFORM(data3D(x1:x2, y2, z1:z2)), sMainState)
  2759.          subImg = BYTSCL(TEMPORARY(subImg), MIN=0B, MAX=255B, $
  2760.                          TOP=sMainState.sColorState.nColor-1)
  2761.          subImg = TEMPORARY(subImg) + $
  2762.                      BYTE(faceDir * sMainState.sColorState.nColor)
  2763.          POLYFILL, [x1,x2,x2,x1], [y2,y2,y2,y2], [z1,z1,z2,z2], $
  2764.             PATTERN=subImg, /T3D, /DATA, IMAGE_INTERP=sMainState.interpMode, $
  2765.             TRANSPARENT=Viz3D_TranspValu(sMainState, faceDir), $
  2766.             IMAGE_COORD=[[0,0],[dim1,0],[dim1,dim2],[0,dim2]]
  2767.       endif
  2768.  
  2769.       norm = [[x2,y2,z2], [x2+1.0,y2,z2]] / dims
  2770.       norm = VERT_T3D(norm, /NO_COPY)
  2771.       if ((norm(2,1)-norm(2,0)) lt 0.0) then begin
  2772.          dim1 = (y2 - y1)
  2773.          dim2 = (z2 - z1)
  2774.          faceDir = 0
  2775.          subImg = $
  2776.             Viz3D_ScaleData(REFORM(data3D(x2, y1:y2, z1:z2)), sMainState)
  2777.          subImg = BYTSCL(TEMPORARY(subImg), MIN=0B, MAX=255B, $
  2778.                          TOP=sMainState.sColorState.nColor-1)
  2779.          subImg = TEMPORARY(subImg) + $
  2780.                      BYTE(faceDir * sMainState.sColorState.nColor)
  2781.          POLYFILL, [x2,x2,x2,x2], [y1,y2,y2,y1], [z1,z1,z2,z2], $
  2782.             PATTERN=subImg, /T3D, /DATA, IMAGE_INTERP=sMainState.interpMode, $
  2783.             TRANSPARENT=Viz3D_TranspValu(sMainState, faceDir), $
  2784.             IMAGE_COORD=[[0,0],[dim1,0],[dim1,dim2],[0,dim2]]
  2785.       endif
  2786.  
  2787.       imageBuffer2 = TVRD()
  2788.       depthBuffer2 = TVRD(CHANNEL=1, /WORDS)
  2789.       depthMask2 = (depthBuffer2 gt (-32765)) and $
  2790.                    (depthBuffer2 lt depthBuffer1)
  2791.       depthMask = WHERE(TEMPORARY(depthMask1) * TEMPORARY(depthMask2))
  2792.  
  2793.       if (depthMask(0) ge 0L) then begin
  2794.          imageBuffer1(depthMask) = imageBuffer2(depthMask)
  2795.          depthBuffer1(depthMask) = depthBuffer2(depthMask)
  2796.       endif
  2797.  
  2798.       TV, imageBuffer1
  2799.       TV, depthBuffer1, CHANNEL=1, /WORDS
  2800.  
  2801.    endelse
  2802.  
  2803.    ; Put the data back.
  2804.    Viz3D_PutData, data3D, sMainState
  2805.  
  2806.    SET_PLOT, sMainState.screenDevice
  2807.  
  2808.    ; Update the big view window.
  2809.    if (NOT(KEYWORD_SET(skipDraw))) then $
  2810.       Viz3D_DrawData, sMainState
  2811.  
  2812.    ; Add block to sMainState.hDisplayList
  2813.    if (NOT(KEYWORD_SET(skipAdd))) then begin
  2814.       HANDLE_VALUE, sMainState.sThreshState.hLowThresh, lowThresh, $
  2815.          /NO_COPY
  2816.       HANDLE_VALUE, sMainState.sThreshState.hHighThresh, highThresh, $
  2817.          /NO_COPY
  2818.       HANDLE_VALUE, sMainState.sThreshState.hTransVal, transVal, $
  2819.          /NO_COPY
  2820.       lTh = lowThresh(sMainState.curData)
  2821.       hTh = highThresh(sMainState.curData)
  2822.       vTp = transVal(sMainState.curData)
  2823.       HANDLE_VALUE, sMainState.sThreshState.hLowThresh, lowThresh, $
  2824.          /NO_COPY, /SET
  2825.       HANDLE_VALUE, sMainState.sThreshState.hHighThresh, highThresh, $
  2826.          /NO_COPY, /SET
  2827.       HANDLE_VALUE, sMainState.sThreshState.hTransVal, transVal, $
  2828.          /NO_COPY, /SET
  2829.       graphic = {VIZ3D_BLOCK, curData:sMainState.curData, $
  2830.                  c1:sMainState.sBlockState.c1, $
  2831.                  c2:sMainState.sBlockState.c2, $
  2832.                  blockMode:sMainState.sBlockState.blockMode, $
  2833.                  lowThresh:lTh, highThresh:hTh, transVal:vTp}
  2834.       h = Viz3D_Add_Graphic(sMainState, graphic, /NO_COPY)
  2835.    endif
  2836.  
  2837.    WIDGET_CONTROL, sMainState.wStatText, SET_VALUE=('')
  2838. end
  2839. ;******************************************************************************
  2840.  
  2841.  
  2842. ;******************************************************************************
  2843. ; Procedure to draw an iso-surface.
  2844. pro Viz3D_SurfDraw, sMainState, hVertList, hPolyList, hColorList, $
  2845.        SKIP_ADD=skipAdd, SKIP_DRAW=skipDraw, CALC_SURF=calcSurf
  2846.  
  2847.    if (KEYWORD_SET(calcSurf)) then begin
  2848.       WIDGET_CONTROL, sMainState.wStatText, $
  2849.          SET_VALUE=('Calculating iso-surface ...')
  2850.  
  2851.       ; Check out the data without making a copy.
  2852.       data3D = Viz3D_GetData(sMainState)
  2853.  
  2854.       HANDLE_VALUE, sMainState.sSurfState.hSurfThresh, surfThresh, /NO_COPY
  2855.       sT = surfThresh(sMainState.curData)
  2856.       HANDLE_VALUE, sMainState.sSurfState.hSurfThresh, surfThresh, $
  2857.          /NO_COPY, /SET
  2858.       SHADE_VOLUME, data3D, sT, vertList, polyList, $
  2859.                     LOW=(sMainState.sSurfState.surfSide eq 0)
  2860.       Viz3D_PutData, data3D, sMainState
  2861.  
  2862.       if (N_ELEMENTS(polyList) le 0L) then begin ; No iso-surface to render.
  2863.          WIDGET_CONTROL, sMainState.wStatText, SET_VALUE=''
  2864.          return
  2865.       endif
  2866.  
  2867.       if (polyList(0) lt 0L) then begin ; No iso-surface to render.
  2868.          WIDGET_CONTROL, sMainState.wStatText, SET_VALUE=''
  2869.          return
  2870.       endif
  2871.  
  2872.       if (sMainState.curData eq sMainState.sSurfState.curShade) then begin
  2873.          ; Light-source shading.
  2874.          colorList = (-1L)
  2875.       endif else begin
  2876.          data3D = $
  2877.             Viz3D_GetData(sMainState, sMainState.sSurfState.curShade)
  2878.          shadeData = data3D
  2879.          Viz3D_PutData, data3D, sMainState, sMainState.sSurfState.curShade
  2880.          colorList = INTERPOLATE(TEMPORARY(shadeData), $
  2881.             vertList(0,*), vertList(1,*), vertList(2,*), MISSING=0)
  2882.          HANDLE_VALUE, sMainState.sThreshState.hLowThresh, lowThresh, $
  2883.             /NO_COPY
  2884.          HANDLE_VALUE, sMainState.sThreshState.hHighThresh, highThresh, $
  2885.             /NO_COPY
  2886.          lTh = lowThresh(sMainState.sSurfState.curShade)
  2887.          hTh = highThresh(sMainState.sSurfState.curShade)
  2888.          HANDLE_VALUE, sMainState.sThreshState.hLowThresh, lowThresh, $
  2889.             /NO_COPY, /SET
  2890.          HANDLE_VALUE, sMainState.sThreshState.hHighThresh, highThresh, $
  2891.             /NO_COPY, /SET
  2892.          colorList = BYTSCL(TEMPORARY(colorList), MIN=lTh, MAX=hTh, $
  2893.             TOP=sMainState.sColorState.nColor-1)
  2894.          colorList = TEMPORARY(colorList) + $
  2895.             BYTE(3 * sMainState.sColorState.nColor)
  2896.       endelse
  2897.  
  2898.       WIDGET_CONTROL, sMainState.wStatText, $
  2899.          SET_VALUE=(STRTRIM((SIZE(vertList))(2),2) + ' Verts, ' + $
  2900.          STRTRIM((SIZE(polyList))(1)/4,2) + ' Polys.')
  2901.    endif else begin
  2902.       WIDGET_CONTROL, sMainState.wStatText, $
  2903.          SET_VALUE=('Drawing iso-surface ...')
  2904.  
  2905.       HANDLE_VALUE, hVertList, vertList, /NO_COPY
  2906.       HANDLE_VALUE, hPolyList, polyList, /NO_COPY
  2907.       HANDLE_VALUE, hColorList, colorList, /NO_COPY
  2908.    endelse
  2909.  
  2910.    SET_PLOT, 'Z'
  2911.  
  2912.    SET_SHADING, /GOURAUD, LIGHT=[-0.5, 0.5, 0.5], REJECT=0, $
  2913.       VALUES=[(sMainState.sColorState.nColor*3), $
  2914.               (sMainState.sColorState.nColor*5)-1]
  2915.  
  2916.    if (colorList(0) lt 0B) then begin ; Light-source shading.
  2917.       nothing = POLYSHADE(vertList, polyList, /DATA, /T3D, $
  2918.          TOP=((sMainState.sColorState.nColor*4)-1))
  2919.    endif else begin ; Data shading.
  2920.       nothing = POLYSHADE(vertList, polyList, /DATA, /T3D, $
  2921.          SHADES=colorList, TOP=((sMainState.sColorState.nColor*4)-1))
  2922.    endelse
  2923.  
  2924.    if not(KEYWORD_SET(calcSurf)) then begin
  2925.       HANDLE_VALUE, hVertList, vertList, /NO_COPY, /SET
  2926.       HANDLE_VALUE, hPolyList, polyList, /NO_COPY, /SET
  2927.       HANDLE_VALUE, hColorList, colorList, /NO_COPY, /SET
  2928.    endif
  2929.  
  2930.    SET_PLOT, sMainState.screenDevice
  2931.  
  2932.    ; Update the big view window.
  2933.    if (NOT(KEYWORD_SET(skipDraw))) then $
  2934.       Viz3D_DrawData, sMainState
  2935.  
  2936.    ; Add surface to sMainState.hDisplayList
  2937.    if (NOT(KEYWORD_SET(skipAdd))) then begin
  2938.       HANDLE_VALUE, sMainState.sSurfState.hSurfThresh, surfThresh, /NO_COPY
  2939.       sT = surfThresh(sMainState.curData)
  2940.       HANDLE_VALUE, sMainState.sSurfState.hSurfThresh, surfThresh, $
  2941.          /NO_COPY, /SET
  2942.       graphic = {VIZ3D_SURF, curData:sMainState.curData, $
  2943.                  hVertList:0L, hPolyList:0L, hColorList:0L, $
  2944.                  surfThresh:sT, surfSide:sMainState.sSurfState.surfSide}
  2945.       h = Viz3D_Add_Graphic(sMainState, graphic, /NO_COPY)
  2946.       if (KEYWORD_SET(calcSurf)) then begin
  2947.          HANDLE_VALUE, h, graphic, /NO_COPY
  2948.          graphic.hVertList = HANDLE_CREATE(h, VALUE=vertList, /NO_COPY)
  2949.          graphic.hPolyList = HANDLE_CREATE(h, VALUE=polyList, /NO_COPY)
  2950.          graphic.hColorList = HANDLE_CREATE(h, VALUE=colorList, /NO_COPY)
  2951.          HANDLE_VALUE, h, graphic, /NO_COPY, /SET
  2952.       endif
  2953.    endif
  2954.  
  2955.    WIDGET_CONTROL, sMainState.wStatText, SET_VALUE=('')
  2956. end
  2957. ;******************************************************************************
  2958.  
  2959.  
  2960. ;******************************************************************************
  2961. ; Procedure to draw a projection.
  2962. pro Viz3D_ProjDraw, sMainState, SKIP_ADD=skipAdd, SKIP_DRAW=skipDraw
  2963.  
  2964.    WIDGET_CONTROL, sMainState.wStatText, $
  2965.       SET_VALUE=('Calculating projection ...')
  2966.  
  2967.    SET_PLOT, 'Z'
  2968.    imageBuffer = TVRD()
  2969.    depthBuffer = TVRD(CHANNEL=1, /WORDS)
  2970.  
  2971.    annoIndex = WHERE(imageBuffer gt (5*sMainState.sColorState.nColor))
  2972.    if (annoIndex(0) ge 0L) then depthBuffer(TEMPORARY(annoIndex)) = (-32765)
  2973.  
  2974.    minDim = sMainState.sViewState.xMax < sMainState.sViewState.yMax < $
  2975.             sMainState.sViewState.zMax
  2976.    maxDim = sMainState.sViewState.xMax > sMainState.sViewState.yMax > $
  2977.             sMainState.sViewState.zMax
  2978.    avgDim = Float(maxDim + minDim) / 2.0
  2979.    case sMainState.sProjState.projReso of
  2980.       0: begin ; Low.
  2981.          xS = ROUND(FLOAT(avgDim) / 2.0) > 2
  2982.          yS = ROUND(FLOAT(avgDim) / 2.0) > 2
  2983.          zS = ROUND(FLOAT(avgDim) / 2.0) > 2
  2984.       end
  2985.       1: begin ; Medium.
  2986.          xS = ROUND(FLOAT(avgDim) / 1.5) > 2
  2987.          yS = ROUND(FLOAT(avgDim) / 1.5) > 2
  2988.          zS = ROUND(FLOAT(avgDim) / 1.5) > 2
  2989.       end
  2990.       2: begin ; high.
  2991.          xS = ROUND(FLOAT(maxDim) / 1.0) > 2
  2992.          yS = ROUND(FLOAT(maxDim) / 1.0) > 2
  2993.          zS = ROUND(FLOAT(maxDim) / 1.0) > 2
  2994.       end
  2995.    endcase
  2996.  
  2997.    ; Calculate the projection.
  2998.  
  2999.    data3D_raw = Viz3D_GetData(sMainState)
  3000.    data3D = data3D_raw
  3001.    Viz3D_PutData, data3D_raw, sMainState
  3002.    data3D = Viz3D_ScaleData(data3D, sMainState)
  3003.  
  3004.    xyS = xS * yS
  3005.  
  3006.    cubePts = FLTARR(8,4)
  3007.    cubePts(0,*) = [0,0,0,1]
  3008.    cubePts(1,*) = [1,0,0,1]
  3009.    cubePts(2,*) = [1,1,0,1]
  3010.    cubePts(3,*) = [0,1,0,1]
  3011.    cubePts(4,*) = [0,0,1,1]
  3012.    cubePts(5,*) = [1,0,1,1]
  3013.    cubePts(6,*) = [1,1,1,1]
  3014.    cubePts(7,*) = [0,1,1,1]
  3015.    cubePts = cubepts # !P.T
  3016.    xMin = MIN(cubePts(*,0), MAX=xMax)
  3017.    yMin = MIN(cubePts(*,1), MAX=yMax)
  3018.    zMin = MIN(cubePts(*,2), MAX=zMax)
  3019.    zRange = zMax - zMin
  3020.  
  3021.    xInd = REFORM(((Findgen(xS) / Float(xS - 1L)) # Replicate(1.0, yS)), xyS)
  3022.    yInd = REFORM((Replicate(1.0, xS) # (Findgen(yS) / Float(yS - 1L))), xyS)
  3023.  
  3024.    index = FLTARR(xyS, 4, /NOZERO)
  3025.    index(0, 0) = TEMPORARY(xInd)
  3026.    index(0, 1) = TEMPORARY(yInd)
  3027.    index(*, 3) = 1.0
  3028.  
  3029.    kMax = zS - 1
  3030.    fkMax = FLOAT(kMax)
  3031.  
  3032.    pDepth = CONGRID(depthBuffer, Xs, Ys, /INTERP, /MINUS_ONE)
  3033.    if (sMainState.sProjState.projType) then $
  3034.       sumImage = FLTARR(xS, yS) $
  3035.    else sumImage = BYTARR(xS, yS)
  3036.  
  3037.    depthQ = (100.0 - sMainState.sProjState.depthQ) / 100.0
  3038.    for k=0, kMax do begin ; Project one plane at a time.
  3039.  
  3040.       fk = FLOAT(k)
  3041.       zVal = ((fk / fkMax) * zRange) + zMin
  3042.       index(*, 2) = zVal
  3043.       tIndex = index # sMainState.sViewState.invTrans
  3044.  
  3045.       indX = ((tIndex(*, 0) / tIndex(*, 3)) - !X.S(0)) / !X.S(1)
  3046.       indY = ((tIndex(*, 1) / tIndex(*, 3)) - !Y.S(0)) / !Y.S(1)
  3047.       indZ = ((tIndex(*, 2) / tIndex(*, 3)) - !Z.S(0)) / !Z.S(1)
  3048.  
  3049.       zPlane = ROUND(2.0 * ((((zVal - 0.5) > (-0.5)) < 0.5) * 32765.0))
  3050.       zInd = WHERE(pDepth lt zPlane)
  3051.  
  3052.       if (zInd(0) ge 0L) then begin ; Something new in front
  3053.          depthFac = BYTE((1.0 - ((zVal-zMin)/(zMax-zMin))) * depthQ * 255.0)
  3054.          tempImg = REFORM(((INTERPOLATE(data3D, indX, indY, indZ, $
  3055.                             MISSING=0B) > depthFac) - depthFac), xS, yS)
  3056.  
  3057.          HANDLE_VALUE, sMainState.sThreshState.hLowThresh, lowThresh, $
  3058.             /NO_COPY
  3059.          HANDLE_VALUE, sMainState.sThreshState.hHighThresh, highThresh, $
  3060.             /NO_COPY
  3061.          HANDLE_VALUE, sMainState.sThreshState.hTransVal, transVal, $
  3062.             /NO_COPY
  3063.          lTh = lowThresh(sMainState.curData)
  3064.          hTh = highThresh(sMainState.curData)
  3065.          vTp = transVal(sMainState.curData)
  3066.          HANDLE_VALUE, sMainState.sThreshState.hLowThresh, lowThresh, $
  3067.             /NO_COPY, /SET
  3068.          HANDLE_VALUE, sMainState.sThreshState.hHighThresh, highThresh, $
  3069.             /NO_COPY, /SET
  3070.          HANDLE_VALUE, sMainState.sThreshState.hTransVal, transVal, $
  3071.             /NO_COPY, /SET
  3072.  
  3073.          transVal = (FLOAT(vTp - lTh) / FLOAT(hTh - lTh)) * 255.0
  3074.          transVal = BYTE((transVal > 0.0) < 255.0)
  3075.          transInd = WHERE(tempImg lt transVal)
  3076.          if (transInd(0) ge 0L) then tempImg(TEMPORARY(transInd)) = 0B
  3077.          if (sMainState.sProjState.projType) then begin ; Avg projection.
  3078.             newVal = FLOAT(tempImg(zInd))
  3079.             setInd = WHERE(sumImage(zInd) lt newVal)
  3080.             sumImage(zInd) = sumImage(zInd) + (TEMPORARY(newVal) / fkMax)
  3081.             if (setInd(0) ge 0L) then begin
  3082.                setInd = zInd(TEMPORARY(setInd))
  3083.                pDepth(TEMPORARY(setInd)) = zPlane
  3084.             endif
  3085.          endif else begin ; Max projection.
  3086.             setInd = WHERE(sumImage(zInd) lt tempImg(zInd))
  3087.             if (setInd(0) ge 0L) then begin
  3088.                setInd = zInd(TEMPORARY(setInd))
  3089.                pDepth(TEMPORARY(setInd)) = zPlane
  3090.             endif
  3091.             sumImage = TEMPORARY(sumImage) > tempImg
  3092.          endelse
  3093.       endif
  3094.    endfor
  3095.    if (sMainState.sProjState.projType) then begin ; Scale the avg projection.
  3096.       minSum = MIN(sumImage, MAX=maxSum)
  3097.       if ((maxSum - minSum) gt 0.0) then $
  3098.          sumImage = (TEMPORARY(sumImage) - minSum) / (maxSum - minSum)
  3099.       HANDLE_VALUE, sMainState.sThreshState.hMinData, minData, /NO_COPY
  3100.       HANDLE_VALUE, sMainState.sThreshState.hMaxData, maxData, /NO_COPY
  3101.       minD = minData(sMainState.curData)
  3102.       maxD = maxData(sMainState.curData)
  3103.       HANDLE_VALUE, sMainState.sThreshState.hMinData, minData, /NO_COPY, /SET
  3104.       HANDLE_VALUE, sMainState.sThreshState.hMaxData, maxData, /NO_COPY, /SET
  3105.       sumImage = (TEMPORARY(sumImage) * (maxD - minD)) + minD
  3106.       sumImage = BYTSCL(TEMPORARY(sumImage), MIN=minD, MAX=maxD, $
  3107.          TOP=sMainState.sColorState.nColor-1)
  3108.    endif else begin
  3109.       sumImage = BYTSCL(TEMPORARY(sumImage), $
  3110.          MIN=0, MAX=255, TOP=sMainState.sColorState.nColor-1)
  3111.    endelse
  3112.  
  3113.    tempImg = 0
  3114.    index = 0
  3115.    tIndex = 0
  3116.    setInd = 0
  3117.    indX = 0
  3118.    indY = 0
  3119.    indZ = 0
  3120.    zInd = 0
  3121.  
  3122.    sBand = (FLOAT(!D.X_Size) / FLOAT(xS)) > (FLOAT(!D.Y_Size) / FLOAT(yS))
  3123.    sBand = ROUND(sBand / 2.0) > 3
  3124.    sumImage = CONGRID(TEMPORARY(sumImage), !D.X_Size, !D.Y_Size, $
  3125.                       /INTERP, /MINUS_ONE)
  3126.    sumImage = SMOOTH(TEMPORARY(sumImage), sBand, /EDGE)
  3127.    pDepth = CONGRID(TEMPORARY(pDepth), !D.X_Size, !D.Y_Size, $
  3128.                     /INTERP, /MINUS_ONE)
  3129.    pDepth = SMOOTH(TEMPORARY(pDepth), sBand, /EDGE)
  3130.    newInd = WHERE(pDepth ge depthBuffer)
  3131.  
  3132.    if (newInd(0) ge 0L) then begin
  3133.       sumImage = TEMPORARY(sumImage) + BYTE(sMainState.sColorState.nColor*4)
  3134.       sumImage = sumImage(newInd)
  3135.       pDepth = pDepth(newInd)
  3136.       imageBuffer(newInd) = TEMPORARY(sumImage)
  3137.       depthBuffer(TEMPORARY(newInd)) = TEMPORARY(pDepth)
  3138.  
  3139.       ERASE
  3140.       TV, TEMPORARY(imageBuffer)
  3141.       TV, TEMPORARY(depthBuffer), CHANNEL=1, /WORDS
  3142.    endif
  3143.  
  3144.    SET_PLOT, sMainState.screenDevice
  3145.  
  3146.    ; Update the big view window.
  3147.    if (NOT(KEYWORD_SET(skipDraw))) then $
  3148.       Viz3D_DrawData, sMainState
  3149.  
  3150.    ; Add projection to sMainState.hDisplayList
  3151.    if (NOT(KEYWORD_SET(skipAdd))) then begin
  3152.       HANDLE_VALUE, sMainState.sThreshState.hLowThresh, lowThresh, $
  3153.          /NO_COPY
  3154.       HANDLE_VALUE, sMainState.sThreshState.hHighThresh, highThresh, $
  3155.          /NO_COPY
  3156.       HANDLE_VALUE, sMainState.sThreshState.hTransVal, transVal, $
  3157.          /NO_COPY
  3158.       lTh = lowThresh(sMainState.curData)
  3159.       hTh = highThresh(sMainState.curData)
  3160.       vTp = transVal(sMainState.curData)
  3161.       HANDLE_VALUE, sMainState.sThreshState.hLowThresh, lowThresh, $
  3162.          /NO_COPY, /SET
  3163.       HANDLE_VALUE, sMainState.sThreshState.hHighThresh, highThresh, $
  3164.          /NO_COPY, /SET
  3165.       HANDLE_VALUE, sMainState.sThreshState.hTransVal, transVal, $
  3166.          /NO_COPY, /SET
  3167.       graphic = {VIZ3D_PROJ, curData:sMainState.curData, $
  3168.                  projType:sMainState.sProjState.projType, $
  3169.                  projReso:sMainState.sProjState.projReso, $
  3170.                  depthQ:sMainState.sProjState.depthQ, $
  3171.                  lowThresh:lTh, highThresh:hTh, transVal:vTp}
  3172.       h = Viz3D_Add_Graphic(sMainState, graphic, /NO_COPY)
  3173.    endif
  3174.  
  3175.    WIDGET_CONTROL, sMainState.wStatText, SET_VALUE=('')
  3176. end
  3177. ;******************************************************************************
  3178.  
  3179.  
  3180. ;******************************************************************************
  3181. ; Procedure to draw the probe in the big window.
  3182. pro Viz3D_ProbeDraw, sMainState
  3183.  
  3184.    lineColor = Viz3D_TransColor(sMainState, sMainState.sProbeState.lineColor)
  3185.  
  3186.    WSET, sMainState.mainWin
  3187.    DEVICE, COPY=[0, 0, sMainState.winX, sMainState.winY, $
  3188.                  0, 0, sMainState.pixWin]
  3189.  
  3190.    PLOTS, [sMainState.sProbeState.x, sMainState.sProbeState.x], $
  3191.           [sMainState.sProbeState.y, sMainState.sProbeState.y], $
  3192.           [0, sMainState.szData(3)-1], $
  3193.           /DATA, /T3D, COLOR=lineColor
  3194.  
  3195.    PLOTS, [sMainState.sProbeState.x, sMainState.sProbeState.x], $
  3196.           [0, sMainState.szData(2)-1], $
  3197.           [sMainState.sProbeState.z, sMainState.sProbeState.z], $
  3198.           /DATA, /T3D, COLOR=lineColor
  3199.  
  3200.    PLOTS, [0, sMainState.szData(1)-1], $
  3201.           [sMainState.sProbeState.y, sMainState.sProbeState.y], $
  3202.           [sMainState.sProbeState.z, sMainState.sProbeState.z], $
  3203.           /DATA, /T3D, COLOR=lineColor
  3204.    EMPTY
  3205.  
  3206.    data3D = Viz3D_GetData(sMainState)
  3207.    dataPt = INTERPOLATE(data3D, sMainState.sProbeState.x, $
  3208.                                 sMainState.sProbeState.y, $
  3209.                                 sMainState.sProbeState.z)
  3210.    Viz3D_PutData, data3D, sMainState
  3211.  
  3212.    WIDGET_CONTROL, sMainState.wStatText, $
  3213.       SET_VALUE=('Data: ' + STRTRIM(STRING(FLOAT(dataPt)), 2))
  3214.    WIDGET_CONTROL, sMainState.sProbeState.wProbeXText, $
  3215.       SET_VALUE=STRTRIM(STRING(sMainState.sProbeState.x), 2)
  3216.    WIDGET_CONTROL, sMainState.sProbeState.wProbeYText, $
  3217.       SET_VALUE=STRTRIM(STRING(sMainState.sProbeState.y), 2)
  3218.    WIDGET_CONTROL, sMainState.sProbeState.wProbeZText, $
  3219.       SET_VALUE=STRTRIM(STRING(sMainState.sProbeState.z), 2)
  3220.  
  3221. end
  3222. ;******************************************************************************
  3223.  
  3224.  
  3225. ;******************************************************************************
  3226. ; Procedure to draw the profile line in the big window.
  3227. pro Viz3D_ProfDraw, sMainState
  3228.  
  3229.    lineColor = Viz3D_TransColor(sMainState, sMainState.sProfState.lineColor)
  3230.    markColor1 = Viz3D_TransColor(sMainState, sMainState.sProfState.markColor1)
  3231.    markColor2 = Viz3D_TransColor(sMainState, sMainState.sProfState.markColor2)
  3232.  
  3233.    WSET, sMainState.mainWin
  3234.    DEVICE, COPY=[0, 0, sMainState.winX, sMainState.winY, $
  3235.                  0, 0, sMainState.pixWin]
  3236.    if (sMainState.sProfState.profType) then begin
  3237.       if ((sMainState.sProfState.z2Obliq ne 0) and $
  3238.           (sMainState.sProfState.z2Obliq ne sMainState.szData(3)-1)) then $
  3239.          PLOTS, [sMainState.sProfState.x2Obliq, $
  3240.                  sMainState.sProfState.x2Obliq], $
  3241.                 [sMainState.sProfState.y2Obliq, $
  3242.                  sMainState.sProfState.y2Obliq], $
  3243.                 [0, sMainState.szData(3)-1], $
  3244.                 /DATA, /T3D, COLOR=markColor2
  3245.       if ((sMainState.sProfState.y2Obliq ne 0) and $
  3246.           (sMainState.sProfState.y2Obliq ne sMainState.szData(2)-1)) then $
  3247.          PLOTS, [sMainState.sProfState.x2Obliq, $
  3248.                  sMainState.sProfState.x2Obliq], $
  3249.                 [0, sMainState.szData(2)-1], $
  3250.                 [sMainState.sProfState.z2Obliq, $
  3251.                  sMainState.sProfState.z2Obliq], $
  3252.                 /DATA, /T3D, COLOR=markColor2
  3253.       if ((sMainState.sProfState.x2Obliq ne 0) and $
  3254.           (sMainState.sProfState.x2Obliq ne sMainState.szData(1)-1)) then $
  3255.          PLOTS, [0, sMainState.szData(1)-1], $
  3256.                 [sMainState.sProfState.y2Obliq, $
  3257.                  sMainState.sProfState.y2Obliq], $
  3258.                 [sMainState.sProfState.z2Obliq, $
  3259.                  sMainState.sProfState.z2Obliq], $
  3260.                 /DATA, /T3D, COLOR=markColor2
  3261.  
  3262.       if ((sMainState.sProfState.z1Obliq ne 0) and $
  3263.           (sMainState.sProfState.z1Obliq ne sMainState.szData(3)-1)) then $
  3264.          PLOTS, [sMainState.sProfState.x1Obliq, $
  3265.                  sMainState.sProfState.x1Obliq], $
  3266.                 [sMainState.sProfState.y1Obliq, $
  3267.                  sMainState.sProfState.y1Obliq], $
  3268.                 [0, sMainState.szData(3)-1], $
  3269.                 /DATA, /T3D, COLOR=markColor1
  3270.       if ((sMainState.sProfState.y1Obliq ne 0) and $
  3271.           (sMainState.sProfState.y1Obliq ne sMainState.szData(2)-1)) then $
  3272.          PLOTS, [sMainState.sProfState.x1Obliq, $
  3273.                  sMainState.sProfState.x1Obliq], $
  3274.                 [0, sMainState.szData(2)-1], $
  3275.                 [sMainState.sProfState.z1Obliq, $
  3276.                  sMainState.sProfState.z1Obliq], $
  3277.                 /DATA, /T3D, COLOR=markColor1
  3278.       if ((sMainState.sProfState.x1Obliq ne 0) and $
  3279.           (sMainState.sProfState.x1Obliq ne sMainState.szData(1)-1)) then $
  3280.          PLOTS, [0, sMainState.szData(1)-1], $
  3281.                 [sMainState.sProfState.y1Obliq, $
  3282.                  sMainState.sProfState.y1Obliq], $
  3283.                 [sMainState.sProfState.z1Obliq, $
  3284.                  sMainState.sProfState.z1Obliq], $
  3285.                 /DATA, /T3D, COLOR=markColor1
  3286.  
  3287.       PLOTS, [sMainState.sProfState.x1Obliq, sMainState.sProfState.x2Obliq], $
  3288.              [sMainState.sProfState.y1Obliq, sMainState.sProfState.y2Obliq], $
  3289.              [sMainState.sProfState.z1Obliq, sMainState.sProfState.z2Obliq], $
  3290.              /DATA, /T3D, COLOR=lineColor
  3291.  
  3292.       WIDGET_CONTROL, sMainState.wStatText, $
  3293.          SET_VALUE=('(' + $
  3294.             STRTRIM(STRING(FIX(sMainState.sProfState.x1Obliq)), 2) + ', ' + $
  3295.             STRTRIM(STRING(FIX(sMainState.sProfState.y1Obliq)), 2) + ', ' + $
  3296.             STRTRIM(STRING(FIX(sMainState.sProfState.z1Obliq)), 2) + $
  3297.                '), (' + $
  3298.             STRTRIM(STRING(FIX(sMainState.sProfState.x2Obliq)), 2) + ', ' + $
  3299.             STRTRIM(STRING(FIX(sMainState.sProfState.y2Obliq)), 2) + ', ' + $
  3300.             STRTRIM(STRING(FIX(sMainState.sProfState.z2Obliq)), 2) + ')')
  3301.    endif else begin
  3302.       PLOTS, [sMainState.sProfState.x1Ortho, sMainState.sProfState.x2Ortho], $
  3303.              [sMainState.sProfState.y1Ortho, sMainState.sProfState.y2Ortho], $
  3304.              [sMainState.sProfState.z1Ortho, sMainState.sProfState.z2Ortho], $
  3305.              /DATA, /T3D, COLOR=lineColor
  3306.       PLOTS, [sMainState.sProfState.x1Ortho], $
  3307.              [sMainState.sProfState.y1Ortho], $
  3308.              [sMainState.sProfState.z1Ortho], $
  3309.              /DATA, /T3D, COLOR=markColor1, PSYM=4, THICK=2
  3310.       PLOTS, [sMainState.sProfState.x2Ortho], $
  3311.              [sMainState.sProfState.y2Ortho], $
  3312.              [sMainState.sProfState.z2Ortho], $
  3313.              /DATA, /T3D, COLOR=markColor2, PSYM=4, THICK=2
  3314.       WIDGET_CONTROL, sMainState.wStatText, $
  3315.          SET_VALUE=('(' + $
  3316.             STRTRIM(STRING(FIX(sMainState.sProfState.x1Ortho)), 2) + ', ' + $
  3317.             STRTRIM(STRING(FIX(sMainState.sProfState.y1Ortho)), 2) + ', ' + $
  3318.             STRTRIM(STRING(FIX(sMainState.sProfState.z1Ortho)), 2) + $
  3319.                '), (' + $
  3320.             STRTRIM(STRING(FIX(sMainState.sProfState.x2Ortho)), 2) + ', ' + $
  3321.             STRTRIM(STRING(FIX(sMainState.sProfState.y2Ortho)), 2) + ', ' + $
  3322.             STRTRIM(STRING(FIX(sMainState.sProfState.z2Ortho)), 2) + ')')
  3323.    endelse
  3324.  
  3325.    EMPTY
  3326.  
  3327. end
  3328. ;******************************************************************************
  3329.  
  3330.  
  3331. ;******************************************************************************
  3332. ; Redraw everything in the display list.
  3333. pro Viz3D_Redraw, sMainState
  3334.  
  3335.    SET_PLOT, 'Z'
  3336.    ERASE
  3337.  
  3338.    hID = HANDLE_INFO(sMainState.hDisplayList, /FIRST_CHILD)
  3339.    while (HANDLE_INFO(hID, /VALID_ID)) do begin
  3340.       HANDLE_VALUE, hID, graphic, /NO_COPY
  3341.       gType = TAG_NAMES(graphic, /STRUCTURE_NAME)
  3342.       case gType of
  3343.          'VIZ3D_ORTHO_PLANE': begin
  3344.             altState = sMainState
  3345.             altState.curData = graphic.curData
  3346.             altState.sSliceState.orthoDir = graphic.orthoDir
  3347.             altState.sSliceState.orthoPos = graphic.orthoPos
  3348.             altState.sSliceState.drawMode = graphic.drawMode
  3349.  
  3350.             HANDLE_VALUE, altState.sThreshState.hLowThresh, lowThresh
  3351.             lowThresh(sMainState.curData) = graphic.lowThresh
  3352.             hLowThresh = HANDLE_CREATE(VALUE=lowThresh, /NO_COPY)
  3353.             altState.sThreshState.hLowThresh = hLowThresh
  3354.  
  3355.             HANDLE_VALUE, altState.sThreshState.hHighThresh, highThresh
  3356.             highThresh(sMainState.curData) = graphic.highThresh
  3357.             hHighThresh = HANDLE_CREATE(VALUE=highThresh, /NO_COPY)
  3358.             altState.sThreshState.hHighThresh = hHighThresh
  3359.  
  3360.             HANDLE_VALUE, altState.sThreshState.hTransVal, transVal
  3361.             transVal(sMainState.curData) = graphic.transVal
  3362.             hTransVal = HANDLE_CREATE(VALUE=transVal, /NO_COPY)
  3363.             altState.sThreshState.hTransVal = hTransVal
  3364.  
  3365.             Viz3D_OrthoPlaneDraw, TEMPORARY(altState), /SKIP_ADD, $
  3366.                /SKIP_DRAW
  3367.  
  3368.             HANDLE_FREE, hLowThresh
  3369.             HANDLE_FREE, hHighThresh
  3370.             HANDLE_FREE, hTransVal
  3371.          end
  3372.          'VIZ3D_OBLIQ_PLANE': begin
  3373.             altState = sMainState
  3374.             altState.curData = graphic.curData
  3375.             altState.sSliceState.drawMode = graphic.drawMode
  3376.             altState.sSliceState.obliqNormal = graphic.obliqNormal
  3377.             altState.sSliceState.obliqCenter = graphic.obliqCenter
  3378.  
  3379.             HANDLE_VALUE, altState.sThreshState.hLowThresh, lowThresh
  3380.             lowThresh(sMainState.curData) = graphic.lowThresh
  3381.             hLowThresh = HANDLE_CREATE(VALUE=lowThresh, /NO_COPY)
  3382.             altState.sThreshState.hLowThresh = hLowThresh
  3383.  
  3384.             HANDLE_VALUE, altState.sThreshState.hHighThresh, highThresh
  3385.             highThresh(sMainState.curData) = graphic.highThresh
  3386.             hHighThresh = HANDLE_CREATE(VALUE=highThresh, /NO_COPY)
  3387.             altState.sThreshState.hHighThresh = hHighThresh
  3388.  
  3389.             HANDLE_VALUE, altState.sThreshState.hTransVal, transVal
  3390.             transVal(sMainState.curData) = graphic.transVal
  3391.             hTransVal = HANDLE_CREATE(VALUE=transVal, /NO_COPY)
  3392.             altState.sThreshState.hTransVal = hTransVal
  3393.  
  3394.             HANDLE_VALUE, graphic.hVertPlane, vertPlane, /NO_COPY
  3395.             HANDLE_VALUE, graphic.hVert3D, vert3D, /NO_COPY
  3396.             Viz3D_ObliqPlaneDraw, TEMPORARY(altState), vertPlane, vert3D, $
  3397.                /SKIP_ADD, /SKIP_DRAW
  3398.             HANDLE_VALUE, graphic.hVert3D, vert3D, /NO_COPY, /SET
  3399.             HANDLE_VALUE, graphic.hVertPlane, vertPlane, /NO_COPY, /SET
  3400.  
  3401.             HANDLE_FREE, hLowThresh
  3402.             HANDLE_FREE, hHighThresh
  3403.             HANDLE_FREE, hTransVal
  3404.          end
  3405.          'VIZ3D_BLOCK': begin
  3406.             altState = sMainState
  3407.             altState.curData = graphic.curData
  3408.             altState.sBlockState.c1 = graphic.c1
  3409.             altState.sBlockState.c2 = graphic.c2
  3410.             altState.sBlockState.blockMode = graphic.blockMode
  3411.  
  3412.             HANDLE_VALUE, altState.sThreshState.hLowThresh, lowThresh
  3413.             lowThresh(sMainState.curData) = graphic.lowThresh
  3414.             hLowThresh = HANDLE_CREATE(VALUE=lowThresh, /NO_COPY)
  3415.             altState.sThreshState.hLowThresh = hLowThresh
  3416.  
  3417.             HANDLE_VALUE, altState.sThreshState.hHighThresh, highThresh
  3418.             highThresh(sMainState.curData) = graphic.highThresh
  3419.             hHighThresh = HANDLE_CREATE(VALUE=highThresh, /NO_COPY)
  3420.             altState.sThreshState.hHighThresh = hHighThresh
  3421.  
  3422.             HANDLE_VALUE, altState.sThreshState.hTransVal, transVal
  3423.             transVal(sMainState.curData) = graphic.transVal
  3424.             hTransVal = HANDLE_CREATE(VALUE=transVal, /NO_COPY)
  3425.             altState.sThreshState.hTransVal = hTransVal
  3426.  
  3427.             Viz3D_BlockDraw, TEMPORARY(altState), /SKIP_ADD, $
  3428.                /SKIP_DRAW
  3429.  
  3430.             HANDLE_FREE, hLowThresh
  3431.             HANDLE_FREE, hHighThresh
  3432.             HANDLE_FREE, hTransVal
  3433.          end
  3434.          'VIZ3D_SURF': begin
  3435.             altState = sMainState
  3436.             altState.curData = graphic.curData
  3437.             altState.sSurfState.surfSide = graphic.surfSide
  3438.  
  3439.             HANDLE_VALUE, altState.sSurfState.hSurfThresh, surfThresh
  3440.             surfThresh(sMainState.curData) = graphic.surfThresh
  3441.             hSurfThresh = HANDLE_CREATE(VALUE=surfThresh, /NO_COPY)
  3442.             altState.sSurfState.hSurfThresh = hSurfThresh
  3443.  
  3444.             Viz3D_SurfDraw, TEMPORARY(altState), graphic.hVertList, $
  3445.                graphic.hPolyList, graphic.hColorList, /SKIP_ADD, /SKIP_DRAW
  3446.  
  3447.             HANDLE_FREE, hSurfThresh
  3448.          end
  3449.          'VIZ3D_PROJ': begin
  3450.             altState = sMainState
  3451.             altState.curData = graphic.curData
  3452.             altState.sProjState.projReso = graphic.projReso
  3453.             altState.sProjState.projType = graphic.projType
  3454.             altState.sProjState.depthQ = graphic.depthQ
  3455.  
  3456.             HANDLE_VALUE, altState.sThreshState.hLowThresh, lowThresh
  3457.             lowThresh(sMainState.curData) = graphic.lowThresh
  3458.             hLowThresh = HANDLE_CREATE(VALUE=lowThresh, /NO_COPY)
  3459.             altState.sThreshState.hLowThresh = hLowThresh
  3460.  
  3461.             HANDLE_VALUE, altState.sThreshState.hHighThresh, highThresh
  3462.             highThresh(sMainState.curData) = graphic.highThresh
  3463.             hHighThresh = HANDLE_CREATE(VALUE=highThresh, /NO_COPY)
  3464.             altState.sThreshState.hHighThresh = hHighThresh
  3465.  
  3466.             HANDLE_VALUE, altState.sThreshState.hTransVal, transVal
  3467.             transVal(sMainState.curData) = graphic.transVal
  3468.             hTransVal = HANDLE_CREATE(VALUE=transVal, /NO_COPY)
  3469.             altState.sThreshState.hTransVal = hTransVal
  3470.  
  3471.             Viz3D_ProjDraw, TEMPORARY(altState), /SKIP_ADD, /SKIP_DRAW
  3472.  
  3473.             HANDLE_FREE, hLowThresh
  3474.             HANDLE_FREE, hHighThresh
  3475.             HANDLE_FREE, hTransVal
  3476.          end
  3477.       endcase
  3478.       HANDLE_VALUE, hID, graphic, /NO_COPY, /SET
  3479.       hID = HANDLE_INFO(hID, /SIBLING)
  3480.    endwhile
  3481.  
  3482.    Viz3D_DrawData, sMainState
  3483.  
  3484. end
  3485. ;******************************************************************************
  3486.  
  3487.  
  3488. ;******************************************************************************
  3489. ; Return an xyz data coordinate on the face of the cube.
  3490. ; This procedure uses the buffers saved in sMainState.frontDepth,
  3491. ; sMainState.backDepth, sMainState.frontImage, and sMainState.backImage
  3492. ; (the Viz3D_FillDepth procedure computes them).
  3493. ; The ON_FACE keyword returns the face that (dX, dY) maps to :
  3494. ;   0- not on any face,  1- XY,   2- XZ,   3- YZ.
  3495. ; (dX, dY) is the 2D screen coordinate (where the user clicked).
  3496. ; invTrans is the inverse of the current view transformation
  3497. ; (from sMainState.sViewState.invTrans).
  3498. function Viz3D_XYZPos, dX, dY, hDepth, hImage, invTrans, ON_FACE=onFace
  3499.  
  3500.    HANDLE_VALUE, hDepth, depthBuffer, /NO_COPY
  3501.    HANDLE_VALUE, hImage, imageBuffer, /NO_COPY
  3502.  
  3503.    szDepth = SIZE(depthBuffer)
  3504.    dX = (dX > 0) < (szDepth(1)-1)
  3505.    dY = (dY > 0) < (szDepth(2)-1)
  3506.    dZ = depthBuffer(dX, dY)
  3507.    onFace = imageBuffer(dX, dY)
  3508.  
  3509.    HANDLE_VALUE, hDepth, depthBuffer, /NO_COPY, /SET
  3510.    HANDLE_VALUE, hImage, imageBuffer, /NO_COPY, /SET
  3511.  
  3512.    zMax = (2L^15L) - 3L
  3513.    zMin = (-zmax)
  3514.  
  3515.    if (dZ le (zMin)) then return, [0.0, 0.0, 0.0] ; Not on any face.
  3516.  
  3517.    nX = Float(dX) / Float(!D.X_Size - 1)
  3518.    nY = Float(dY) / Float(!D.Y_Size - 1)
  3519.    nZ = (Float(dZ) - Float(zMin)) / Float(zMax - zMin)
  3520.  
  3521.    xyzNorm = [nX, nY, nZ, 1.0] # invTrans
  3522.    xyzNorm = xyzNorm / xyzNorm(3)
  3523.  
  3524.    xPos = (xyzNorm(0) - !X.S(0)) / !X.S(1)
  3525.    yPos = (xyzNorm(1) - !Y.S(0)) / !Y.S(1)
  3526.    zPos = (xyzNorm(2) - !Z.S(0)) / !Z.S(1)
  3527.  
  3528.    ; Return the 3D data coordinate on a face of the cube.
  3529.    return, [xPos, yPos, zPos]
  3530.  
  3531. end
  3532. ;******************************************************************************
  3533.  
  3534.  
  3535. ;******************************************************************************
  3536. ; Event handler for slice events.
  3537. pro Viz3D_SliceEvent, event
  3538.  
  3539.    WIDGET_CONTROL, event.id, GET_UVALUE=uVal
  3540.  
  3541.    if (uVal eq 'wMainDraw') then begin
  3542.       wDrawBase = WIDGET_INFO(event.id, /PARENT)
  3543.       WIDGET_CONTROL, wDrawBase, GET_UVALUE=wMainBase
  3544.    endif else begin
  3545.       wMainBase = event.top
  3546.       WIDGET_CONTROL, /HOURGLASS
  3547.    endelse
  3548.  
  3549.    WIDGET_CONTROL, wMainBase, GET_UVALUE=sMainState, /NO_COPY
  3550.  
  3551.    case uVal of
  3552.       'wMainDraw': begin ; Big view window.
  3553.          if (event.release ge 1) then begin
  3554.             WIDGET_CONTROL, sMainState.wMainDraw, DRAW_MOTION_EVENTS=0, $
  3555.                /DRAW_BUTTON_EVENTS
  3556.             WIDGET_CONTROL, /HOURGLASS
  3557.          endif
  3558.  
  3559.          if (event.release gt 1) then begin ; Toggle plane direction.
  3560.             if (sMainState.sSliceState.planeMode eq 1) then begin
  3561.                case sMainState.sSliceState.orthoDir of
  3562.                   1: begin ; X, toggle to Y.
  3563.                      sMainState.sSliceState.orthoDir = 2
  3564.                      WIDGET_CONTROL,sMainState.sSliceState.wSliceYBttn, $
  3565.                         /SET_BUTTON
  3566.                   end
  3567.                   2: begin ; Y, toggle to Z.
  3568.                      sMainState.sSliceState.orthoDir = 3
  3569.                      WIDGET_CONTROL,sMainState.sSliceState.wSliceZBttn, $
  3570.                         /SET_BUTTON
  3571.                   end
  3572.                   3: begin ; Z, toggle to X.
  3573.                      sMainState.sSliceState.orthoDir = 1
  3574.                      WIDGET_CONTROL,sMainState.sSliceState.wSliceXBttn, $
  3575.                         /SET_BUTTON
  3576.                   end
  3577.                endcase
  3578.                Viz3D_SliceShow, sMainState
  3579.             endif
  3580.          endif
  3581.  
  3582.          if ((event.press eq 1) or $
  3583.             ((event.press eq 0) and (event.release eq 0))) then begin
  3584.  
  3585.             if (event.press eq 1) then begin
  3586.                ; Initiate dynamic plane positioning.
  3587.                WIDGET_CONTROL, sMainState.wMainDraw, /DRAW_MOTION_EVENTS, $
  3588.                   /DRAW_BUTTON_EVENTS
  3589.                sMainState.cleanupView = 1
  3590.             endif
  3591.  
  3592.             ; Compute a 3D cube surface location from the current
  3593.             ; cursor position.
  3594.             xyzPos = Viz3D_XYZPos(event.x, event.y, sMainState.hFrontDepth, $
  3595.                sMainState.hFrontImage, sMainState.sViewState.invTrans, $
  3596.                ON_FACE=onFace)
  3597.             ; Normalize the 3D coordinate.
  3598.             xyzPos = Temporary(xyzPos) / [sMainState.sViewState.xMax, $
  3599.                sMainState.sViewState.yMax, sMainState.sViewState.zMax]
  3600.  
  3601.             DEVICE, COPY=[0, 0, sMainState.winX, sMainState.winY, 0, 0, $
  3602.                           sMainState.pixWin]
  3603.  
  3604.             if (onFace gt 0) then begin
  3605.                ; Cursor position is currently somewhere on the cube.
  3606.  
  3607.                if (sMainState.sSliceState.planeMode eq 1) then begin
  3608.                   ; Drag an orthogonal plane.
  3609.  
  3610.                   case sMainState.sSliceState.orthoDir of
  3611.                      1: begin ; X
  3612.                         Plots, xyzPos(0), [0,1,1,0,0], [0,0,1,1,0], /NORMAL, $
  3613.                            /T3D, COLOR=Viz3D_TransColor(sMainState, $
  3614.                            sMainState.sSliceState.edgeColor)
  3615.  
  3616.                         WIDGET_CONTROL, sMainState.wStatText, $
  3617.                            SET_VALUE=('X: ' + $
  3618.                            STRING(xyzPos(0)*sMainState.sViewState.xMax))
  3619.                      end
  3620.                      2: begin ; Y
  3621.                         Plots, [0,1,1,0,0], xyzPos(1), [0,0,1,1,0], /NORMAL, $
  3622.                            /T3D, COLOR=Viz3D_TransColor(sMainState, $
  3623.                            sMainState.sSliceState.edgeColor)
  3624.  
  3625.                         WIDGET_CONTROL, sMainState.wStatText, $
  3626.                            SET_VALUE=('Y: ' + $
  3627.                            STRING(xyzPos(1)*sMainState.sViewState.yMax))
  3628.                      end
  3629.                      3: begin ; Z
  3630.                         Plots, [0,1,1,0,0], [0,0,1,1,0], xyzPos(2), /NORMAL, $
  3631.                            /T3D, COLOR=Viz3D_TransColor(sMainState, $
  3632.                            sMainState.sSliceState.edgeColor)
  3633.  
  3634.                         WIDGET_CONTROL, sMainState.wStatText, $
  3635.                            SET_VALUE=('Z: ' + $
  3636.                            STRING(xyzPos(2)*sMainState.sViewState.zMax))
  3637.                      end
  3638.                   endcase
  3639.                   EMPTY
  3640.  
  3641.                endif else begin ; Drag an oblique plane.
  3642.  
  3643.                   edgeColor = Viz3D_TransColor(sMainState, $
  3644.                                  sMainState.sSliceState.edgeColor)
  3645.                   normColor = Viz3D_TransColor(sMainState, $
  3646.                                  sMainState.sSliceState.normColor)
  3647.  
  3648.                   ; Move plane normal.
  3649.  
  3650.                   if (sMainState.sSliceState.obliqMove eq 0) then begin
  3651.                      sMainState.sSliceState.obliqNormal = $
  3652.                         xyzPos - sMainState.sSliceState.obliqCenter
  3653.                      maxDim = sMainState.sViewState.xMax > $
  3654.                               sMainState.sViewState.yMax > $
  3655.                               sMainState.sViewState.zMax
  3656.                      sMainState.sSliceState.obliqNormal(0) = $
  3657.                         sMainState.sSliceState.obliqNormal(0) * $
  3658.                         sMainState.sViewState.xMax / maxDim
  3659.                      sMainState.sSliceState.obliqNormal(1) = $
  3660.                         sMainState.sSliceState.obliqNormal(1) * $
  3661.                         sMainState.sViewState.yMax / maxDim
  3662.                      sMainState.sSliceState.obliqNormal(2) = $
  3663.                         sMainState.sSliceState.obliqNormal(2) * $
  3664.                         sMainState.sViewState.zMax / maxDim
  3665.                      Viz3D_DrawSliceOblique, $
  3666.                         sMainState.sSliceState.obliqCenter, $
  3667.                         sMainState.sSliceState.obliqNormal, 0, edgeColor, $
  3668.                         sMainState.sViewState.xMax, $
  3669.                         sMainState.sViewState.yMax, $
  3670.                         sMainState.sViewState.zMax, $
  3671.                         sMainState.sViewState.zScale, $
  3672.                         NORMCOLOR=normColor, /SKIP_FILL
  3673.                      sMainState.sSliceState.obliqNormal = $
  3674.                         sMainState.sSliceState.obliqNormal / $
  3675.                         SQRT(TOTAL(sMainState.sSliceState.obliqNormal^2))
  3676.                      WIDGET_CONTROL, sMainState.wStatText, $
  3677.                         SET_VALUE=('Normal: ' + $
  3678.                         STRING(sMainState.sSliceState.obliqNormal, $
  3679.                            FORMAT='(F6.3,1X,F6.3,1X,F6.3)'))
  3680.  
  3681.                   endif else begin ; Move plane center.
  3682.  
  3683.                      case onFace of
  3684.                         1: begin
  3685.                            sMainState.sSliceState.obliqCenter([0,1]) = $
  3686.                               xyzPos([0,1])
  3687.                         end
  3688.                         2: begin
  3689.                            sMainState.sSliceState.obliqCenter([0,2]) = $
  3690.                               xyzPos([0,2])
  3691.                         end
  3692.                         3: begin
  3693.                            sMainState.sSliceState.obliqCenter([1,2]) = $
  3694.                               xyzPos([1,2])
  3695.                         end
  3696.                      endcase
  3697.                      Viz3D_DrawSliceOblique, $
  3698.                         sMainState.sSliceState.obliqCenter, $
  3699.                         sMainState.sSliceState.obliqNormal, 0, edgeColor, $
  3700.                         sMainState.sViewState.xMax, $
  3701.                         sMainState.sViewState.yMax, $
  3702.                         sMainState.sViewState.zMax, $
  3703.                         sMainState.sViewState.zScale, $
  3704.                         NORMCOLOR=normColor, /SKIP_FILL
  3705.                      xyzPos = sMainState.sSliceState.obliqCenter * $
  3706.                               [sMainState.sViewState.xMax, $
  3707.                                sMainState.sViewState.yMax, $
  3708.                                sMainState.sViewState.zMax]
  3709.                      WIDGET_CONTROL, sMainState.wStatText, $
  3710.                         SET_VALUE=('Center: ' + $
  3711.                         STRING(xyzPos, FORMAT='(F6.3,1X,F6.3,1X,F6.3)'))
  3712.                   endelse
  3713.                endelse
  3714.             endif
  3715.          endif
  3716.  
  3717.          if (event.release eq 1) then begin ; Cleanup and draw slice.
  3718.             xyzPos = Viz3D_XYZPos(event.x, event.y, sMainState.hFrontDepth, $
  3719.                sMainState.hFrontImage, sMainState.sViewState.invTrans, $
  3720.                ON_FACE=onFace)
  3721.             xyzPos = Temporary(xyzPos) / [sMainState.sViewState.xMax, $
  3722.                sMainState.sViewState.yMax, sMainState.sViewState.zMax]
  3723.  
  3724.             if (TOTAL(ABS(xyzPos)) gt 0.0) then begin
  3725.                ; Plane is now positioned.
  3726.  
  3727.                if (sMainState.sSliceState.planeMode eq 1) then begin
  3728.                   ; Orthogonal plane.
  3729.                   case sMainState.sSliceState.orthoDir of
  3730.                      1: sMainState.sSliceState.orthoPos = xyzPos(0)
  3731.                      2: sMainState.sSliceState.orthoPos = xyzPos(1)
  3732.                      3: sMainState.sSliceState.orthoPos = xyzPos(2)
  3733.                   endcase
  3734.                   ; Update the small slice status window.
  3735.                   Viz3D_SliceShow, sMainState
  3736.  
  3737.                   ; Draw orthogonal slice with data in the big window.
  3738.                   Viz3D_OrthoPlaneDraw, sMainState
  3739.                endif else begin ; Oblique plane.
  3740.                   ; Normal moved.
  3741.                   if (sMainState.sSliceState.obliqMove eq 0) then begin
  3742.                      sMainState.sSliceState.obliqNormal = $
  3743.                         xyzPos - sMainState.sSliceState.obliqCenter
  3744.                      maxDim = sMainState.sViewState.xMax > $
  3745.                               sMainState.sViewState.yMax > $
  3746.                               sMainState.sViewState.zMax
  3747.                      sMainState.sSliceState.obliqNormal(0) = $
  3748.                         sMainState.sSliceState.obliqNormal(0) * $
  3749.                         sMainState.sViewState.xMax / maxDim
  3750.                      sMainState.sSliceState.obliqNormal(1) = $
  3751.                         sMainState.sSliceState.obliqNormal(1) * $
  3752.                         sMainState.sViewState.yMax / maxDim
  3753.                      sMainState.sSliceState.obliqNormal(2) = $
  3754.                         sMainState.sSliceState.obliqNormal(2) * $
  3755.                         sMainState.sViewState.zMax / maxDim
  3756.                   endif else begin ; Center moved.
  3757.                      case onFace of
  3758.                         1: begin
  3759.                            sMainState.sSliceState.obliqCenter([0,1]) = $
  3760.                               xyzPos([0,1])
  3761.                         end
  3762.                         2: begin
  3763.                            sMainState.sSliceState.obliqCenter([0,2]) = $
  3764.                               xyzPos([0,2])
  3765.                         end
  3766.                         3: begin
  3767.                            sMainState.sSliceState.obliqCenter([1,2]) = $
  3768.                               xyzPos([1,2])
  3769.                         end
  3770.                      endcase
  3771.                   endelse
  3772.                   fillColor = Viz3D_TransColor(sMainState, $
  3773.                                  sMainState.sSliceState.fillColor)
  3774.                   edgeColor = Viz3D_TransColor(sMainState, $
  3775.                                  sMainState.sSliceState.edgeColor)
  3776.                   normColor = Viz3D_TransColor(sMainState, $
  3777.                                  sMainState.sSliceState.normColor)
  3778.                   backColor = Viz3D_TransColor(sMainState, $
  3779.                                  sMainState.backColor)
  3780.  
  3781.                   ; Update the small slice status window.
  3782.                   Viz3D_SliceShow, sMainState
  3783.                endelse
  3784.             endif
  3785.          endif
  3786.       end
  3787.       'wSliceDraw': begin ; Event in small slice plane window.
  3788.          if (event.release gt 0) then begin
  3789.             ; Toggle the orthogonal plane direction.
  3790.  
  3791.             if (sMainState.sSliceState.planeMode eq 1) then begin
  3792.                case sMainState.sSliceState.orthoDir of
  3793.                   1: begin
  3794.                      sMainState.sSliceState.orthoDir = 2
  3795.                      WIDGET_CONTROL,sMainState.sSliceState.wSliceYBttn, $
  3796.                         /SET_BUTTON
  3797.                   end
  3798.                   2: begin
  3799.                      sMainState.sSliceState.orthoDir = 3
  3800.                      WIDGET_CONTROL,sMainState.sSliceState.wSliceZBttn, $
  3801.                         /SET_BUTTON
  3802.                   end
  3803.                   3: begin
  3804.                      sMainState.sSliceState.orthoDir = 1
  3805.                      WIDGET_CONTROL,sMainState.sSliceState.wSliceXBttn, $
  3806.                         /SET_BUTTON
  3807.                   end
  3808.                endcase
  3809.             endif else begin ; Reset the oblique slicing plane position.
  3810.                sMainState.sSliceState.obliqCenter = [0.5, 0.5, 0.5]
  3811.                sMainState.sSliceState.obliqNormal = [0.0, 0.0, 1.0]
  3812.             endelse
  3813.  
  3814.             ; Update the small slice status window.
  3815.             Viz3D_SliceShow, sMainState
  3816.             DEVICE, COPY=[0, 0, sMainState.winX, sMainState.winY, $
  3817.                           0, 0, sMainState.pixWin]
  3818.  
  3819.             WIDGET_CONTROL, sMainState.wStatText, SET_VALUE=''
  3820.          endif
  3821.       end
  3822.       'wSliceOrthoBttn': begin ; Set orthogonal slice mode.
  3823.          sMainState.sSliceState.planeMode = 1
  3824.          WIDGET_CONTROL, sMainState.sSliceState.wSliceObliqBase, MAP=0
  3825.          WIDGET_CONTROL, sMainState.sSliceState.wSliceOrthoBase, MAP=1
  3826.          Viz3D_SliceShow, sMainState
  3827.          DEVICE, COPY=[0, 0, sMainState.winX, sMainState.winY, $
  3828.                        0, 0, sMainState.pixWin]
  3829.          WIDGET_CONTROL, sMainState.wStatText, SET_VALUE=''
  3830.       end
  3831.       'wSliceObliqBttn': begin ; Set oblique slice mode.
  3832.          sMainState.sSliceState.planeMode = 0
  3833.          WIDGET_CONTROL, sMainState.sSliceState.wSliceOrthoBase, MAP=0
  3834.          WIDGET_CONTROL, sMainState.sSliceState.wSliceObliqBase, MAP=1
  3835.          fillColor = Viz3D_TransColor(sMainState, $
  3836.                         sMainState.sSliceState.fillColor)
  3837.          edgeColor = Viz3D_TransColor(sMainState, $
  3838.                         sMainState.sSliceState.edgeColor)
  3839.          normColor = Viz3D_TransColor(sMainState, $
  3840.                         sMainState.sSliceState.normColor)
  3841.          backColor = Viz3D_TransColor(sMainState, $
  3842.                         sMainState.backColor)
  3843.          Viz3D_SliceShow, sMainState
  3844.       end
  3845.       'wSliceDrawBttn': begin ; Set "Draw" mode for slices.
  3846.          sMainState.sSliceState.drawMode = 0
  3847.       end
  3848.       'wSliceExpoBttn': begin ; Set "Expose" mode for slices.
  3849.          sMainState.sSliceState.drawMode = 1
  3850.       end
  3851.       'wSliceXBttn': begin ; Set orthogonal slice direction X.
  3852.          sMainState.sSliceState.orthoDir = 1
  3853.          Viz3D_SliceShow, sMainState
  3854.       end
  3855.       'wSliceYBttn': begin ; Set orthogonal slice direction Y.
  3856.          sMainState.sSliceState.orthoDir = 2
  3857.          Viz3D_SliceShow, sMainState
  3858.       end
  3859.       'wSliceZBttn': begin ; Set orthogonal slice direction Z.
  3860.          sMainState.sSliceState.orthoDir = 3
  3861.          Viz3D_SliceShow, sMainState
  3862.       end
  3863.       'wSliceNormalBttn': begin ; Set oblique slice mode for normal movement.
  3864.          sMainState.sSliceState.obliqMove = 0
  3865.       end
  3866.       'wSliceCenterBttn': begin ; Set oblique slice mode for center movement.
  3867.          sMainState.sSliceState.obliqMove = 1
  3868.       end
  3869.       'wSliceObliqGoBttn': begin ; Draw the slice.
  3870.          fillColor = Viz3D_TransColor(sMainState, $
  3871.                         sMainState.sSliceState.fillColor)
  3872.          edgeColor = Viz3D_TransColor(sMainState, $
  3873.                         sMainState.sSliceState.edgeColor)
  3874.          Viz3D_DrawSliceOblique, sMainState.sSliceState.obliqCenter, $
  3875.             sMainState.sSliceState.obliqNormal, $
  3876.             fillColor, edgeColor, $
  3877.             sMainState.sViewState.xMax, $
  3878.             sMainState.sViewState.yMax, $
  3879.             sMainState.sViewState.zMax, $
  3880.             sMainState.sViewState.zScale, /SKIP_FILL, $
  3881.             VERT_PLANE=vertPlane, VERT_3D=vert3D
  3882.          ; Draw oblique slice with data in the big window.
  3883.          Viz3D_ObliqPlaneDraw, sMainState, vertPlane, vert3D
  3884.       end
  3885.       else:
  3886.    endcase
  3887.  
  3888.    WIDGET_CONTROL, wMainBase, SET_UVALUE=sMainState, /NO_COPY
  3889.  
  3890. end
  3891. ;******************************************************************************
  3892.  
  3893.  
  3894. ;******************************************************************************
  3895. ; Event handler for block events.
  3896. pro Viz3D_BlockEvent, event
  3897.  
  3898.    WIDGET_CONTROL, event.id, GET_UVALUE=uVal
  3899.    if (uVal eq 'wMainDraw') then begin
  3900.       wDrawBase = WIDGET_INFO(event.id, /PARENT)
  3901.       WIDGET_CONTROL, wDrawBase, GET_UVALUE=wMainBase
  3902.    endif else begin
  3903.       wMainBase = event.top
  3904.       WIDGET_CONTROL, /HOURGLASS
  3905.    endelse
  3906.  
  3907.    WIDGET_CONTROL, wMainBase, GET_UVALUE=sMainState, /NO_COPY
  3908.  
  3909.    case uVal of
  3910.       'wMainDraw': begin ; Big draw window, move block.
  3911.          if (event.release ge 1) then begin
  3912.             WIDGET_CONTROL, sMainState.wMainDraw, DRAW_MOTION_EVENTS=0, $
  3913.                /DRAW_BUTTON_EVENTS
  3914.             WIDGET_CONTROL, /HOURGLASS
  3915.          endif
  3916.  
  3917.          if ((event.press ge 1) or $
  3918.             ((event.press eq 0) and (event.release eq 0))) then begin
  3919.  
  3920.             if (event.press ge 1) then begin
  3921.                ; Initiate dynamic block positioning.
  3922.                WIDGET_CONTROL, sMainState.wMainDraw, /DRAW_MOTION_EVENTS, $
  3923.                   /DRAW_BUTTON_EVENTS
  3924.                sMainState.cleanupView = 1
  3925.             endif
  3926.             if (event.press eq 1) then $
  3927.                sMainState.sBlockState.frontBack = 1
  3928.             if (event.press gt 1) then $
  3929.                sMainState.sBlockState.frontBack = 0
  3930.  
  3931.             ; Compute a 3D cube surface location from the current
  3932.             ; cursor position.
  3933.             xyzPos = Viz3D_XYZPos(event.x, event.y, sMainState.hFrontDepth, $
  3934.                sMainState.hFrontImage, sMainState.sViewState.invTrans, $
  3935.                ON_FACE=onFace)
  3936.  
  3937.             xyzPos = ROUND(xyzPos)
  3938.  
  3939.             if (onFace gt 0) then begin ; On cube, draw block.
  3940.                case (onFace) of
  3941.                   1: begin
  3942.                      if (sMainState.sBlockState.frontBack) then begin
  3943.                         sMainState.sBlockState.c1(0) = xyzPos(0)
  3944.                         sMainState.sBlockState.c1(1) = xyzPos(1)
  3945.                      endif else begin
  3946.                         sMainState.sBlockState.c2(0) = xyzPos(0)
  3947.                         sMainState.sBlockState.c2(1) = xyzPos(1)
  3948.                      endelse
  3949.                   end
  3950.                   2: begin
  3951.                      if (sMainState.sBlockState.frontBack) then begin
  3952.                         sMainState.sBlockState.c1(0) = xyzPos(0)
  3953.                         sMainState.sBlockState.c1(2) = xyzPos(2)
  3954.                      endif else begin
  3955.                         sMainState.sBlockState.c2(0) = xyzPos(0)
  3956.                         sMainState.sBlockState.c2(2) = xyzPos(2)
  3957.                      endelse
  3958.                   end
  3959.                   3: begin
  3960.                      if (sMainState.sBlockState.frontBack) then begin
  3961.                         sMainState.sBlockState.c1(1) = xyzPos(1)
  3962.                         sMainState.sBlockState.c1(2) = xyzPos(2)
  3963.                      endif else begin
  3964.                         sMainState.sBlockState.c2(1) = xyzPos(1)
  3965.                         sMainState.sBlockState.c2(2) = xyzPos(2)
  3966.                      endelse
  3967.                   end
  3968.                endcase
  3969.             endif
  3970.          endif
  3971.  
  3972.          DEVICE, COPY=[0, 0, sMainState.winX, sMainState.winY, 0, 0, $
  3973.                        sMainState.pixWin]
  3974.          Viz3D_BlockShow, sMainState, /DIRECT
  3975.  
  3976.          if (event.release ge 1) then begin ; Cleanup.
  3977.             Viz3D_BlockShow, sMainState
  3978.          endif
  3979.  
  3980.          WIDGET_CONTROL, sMainState.wStatText, $
  3981.             SET_VALUE=('(' + $
  3982.             STRTRIM(STRING(sMainState.sBlockState.c1(0)),2) + ', ' + $
  3983.             STRTRIM(STRING(sMainState.sBlockState.c1(1)),2) + ', ' + $
  3984.             STRTRIM(STRING(sMainState.sBlockState.c1(2)),2) + '), (' + $
  3985.             STRTRIM(STRING(sMainState.sBlockState.c2(0)),2) + ', ' + $
  3986.             STRTRIM(STRING(sMainState.sBlockState.c2(1)),2) + ', ' + $
  3987.             STRTRIM(STRING(sMainState.sBlockState.c2(2)),2) + ')')
  3988.  
  3989.       end
  3990.       'wBlockDraw': ; Small block window, do nothing.
  3991.       'wBlockAddBttn': sMainState.sBlockState.blockMode = 1
  3992.       'wBlockSubBttn': sMainState.sBlockState.blockMode = 0
  3993.       'wBlockGoBttn': begin ; Draw it.
  3994.          Viz3D_BlockDraw, sMainState
  3995.       end
  3996.    endcase
  3997.  
  3998.    WIDGET_CONTROL, wMainBase, SET_UVALUE=sMainState, /NO_COPY
  3999. end
  4000. ;******************************************************************************
  4001.  
  4002.  
  4003. ;******************************************************************************
  4004. ; Event handler for surface events.
  4005. pro Viz3D_SurfEvent, event
  4006.  
  4007.    WIDGET_CONTROL, event.id, GET_UVALUE=uVal
  4008.    if (uVal ne 'wSurfDraw') then WIDGET_CONTROL, /HOURGLASS
  4009.  
  4010.    if (uVal eq 'wMainDraw') then begin
  4011.       wDrawBase = WIDGET_INFO(event.id, /PARENT)
  4012.       WIDGET_CONTROL, wDrawBase, GET_UVALUE=wMainBase
  4013.    endif else wMainBase = event.top
  4014.  
  4015.    WIDGET_CONTROL, wMainBase, GET_UVALUE=sMainState, /NO_COPY
  4016.  
  4017.    case uVal of
  4018.       'wMainDraw': ; Big draw window, do nothing.
  4019.       'wSurfDraw': begin
  4020.          if (event.release le 0) then begin
  4021.             ; Determine which to set, high or low.
  4022.             WSET, sMainState.sThreshState.threshWin
  4023.             norm = FLOAT(event.x) / FLOAT(!D.X_SIZE)
  4024.             norm = (norm - 0.03) / (0.97 - 0.03)
  4025.             HANDLE_VALUE, sMainState.sThreshState.hLowThresh, lowThresh, $
  4026.                /NO_COPY
  4027.             HANDLE_VALUE, sMainState.sThreshState.hHighThresh, highThresh, $
  4028.                /NO_COPY
  4029.             lTh = lowThresh(sMainState.curData)
  4030.             hTh = highThresh(sMainState.curData)
  4031.             HANDLE_VALUE, sMainState.sThreshState.hLowThresh, lowThresh, $
  4032.                /NO_COPY, /SET
  4033.             HANDLE_VALUE, sMainState.sThreshState.hHighThresh, highThresh, $
  4034.                /NO_COPY, /SET
  4035.             newThresh = (norm * (hTh - lTh)) + lTh
  4036.             HANDLE_VALUE, sMainState.sSurfState.hSurfThresh, surfThresh, $
  4037.                /NO_COPY
  4038.             surfThresh(sMainState.curData) = newThresh
  4039.             HANDLE_VALUE, sMainState.sSurfState.hSurfThresh, surfThresh, $
  4040.                /NO_COPY, /SET
  4041.             WIDGET_CONTROL, event.id, /DRAW_MOTION_EVENTS, $
  4042.                /DRAW_BUTTON_EVENTS
  4043.             WSET, sMainState.mainWin
  4044.          endif else begin
  4045.             WIDGET_CONTROL, event.id, DRAW_MOTION_EVENTS=0, $
  4046.                /DRAW_BUTTON_EVENTS
  4047.             WIDGET_CONTROL, /HOURGLASS
  4048.          endelse
  4049.  
  4050.          Viz3D_SurfShow, sMainState
  4051.  
  4052.       end
  4053.       'wSurfText': begin
  4054.          WIDGET_CONTROL, event.id, GET_VALUE=newThresh
  4055.          HANDLE_VALUE, sMainState.sThreshState.hLowThresh, lowThresh, $
  4056.             /NO_COPY
  4057.          HANDLE_VALUE, sMainState.sThreshState.hHighThresh, highThresh, $
  4058.             /NO_COPY
  4059.          lTh = lowThresh(sMainState.curData)
  4060.          hTh = highThresh(sMainState.curData)
  4061.          HANDLE_VALUE, sMainState.sThreshState.hLowThresh, lowThresh, $
  4062.             /NO_COPY, /SET
  4063.          HANDLE_VALUE, sMainState.sThreshState.hHighThresh, highThresh, $
  4064.             /NO_COPY, /SET
  4065.          newThresh = FLOAT(newThresh(0))
  4066.          newThresh = (newThresh > lTh) < hTh
  4067.          HANDLE_VALUE, sMainState.sSurfState.hSurfThresh, surfThresh, $
  4068.             /NO_COPY
  4069.          surfThresh(sMainState.curData) = newThresh
  4070.          HANDLE_VALUE, sMainState.sSurfState.hSurfThresh, surfThresh, $
  4071.             /NO_COPY, /SET
  4072.          WIDGET_CONTROL, event.id, SET_VALUE=STRTRIM(STRING(newThresh),2)
  4073.          Viz3D_SurfShow, sMainState
  4074.       end
  4075.       'wSurfLowBttn': sMainState.sSurfState.surfSide = 0
  4076.       'wSurfHighBttn': sMainState.sSurfState.surfSide = 1
  4077.       'wSurfShadeDrop': sMainState.sSurfState.curShade = event.index
  4078.       'wSurfGoBttn': Viz3D_SurfDraw, sMainState, /CALC_SURF
  4079.    endcase
  4080.  
  4081.    WIDGET_CONTROL, wMainBase, SET_UVALUE=sMainState, /NO_COPY
  4082. end
  4083. ;******************************************************************************
  4084.  
  4085.  
  4086. ;******************************************************************************
  4087. ; Event handler for projection events.
  4088. pro Viz3D_ProjectEvent, event
  4089.    WIDGET_CONTROL, /HOURGLASS
  4090.  
  4091.    WIDGET_CONTROL, event.id, GET_UVALUE=uVal
  4092.    if (uVal eq 'wMainDraw') then begin
  4093.       wDrawBase = WIDGET_INFO(event.id, /PARENT)
  4094.       WIDGET_CONTROL, wDrawBase, GET_UVALUE=wMainBase
  4095.    endif else wMainBase = event.top
  4096.  
  4097.    WIDGET_CONTROL, wMainBase, GET_UVALUE=sMainState, /NO_COPY
  4098.  
  4099.    case uVal of
  4100.       'wMainDraw': ; Big draw window, do nothing.
  4101.       'wProjMaxBttn': sMainState.sProjState.projType = 0
  4102.       'wProjAvgBttn': sMainState.sProjState.projType = 1
  4103.       'wProjLowBttn': sMainState.sProjState.projReso = 0
  4104.       'wProjMedBttn': sMainState.sProjState.projReso = 1
  4105.       'wProjHighBttn': sMainState.sProjState.projReso = 2
  4106.       'wProjDQSlid': sMainState.sProjState.depthQ = event.value
  4107.       'wProjGoBttn': Viz3D_ProjDraw, sMainState
  4108.    endcase
  4109.  
  4110.    WIDGET_CONTROL, wMainBase, SET_UVALUE=sMainState, /NO_COPY
  4111. end
  4112. ;******************************************************************************
  4113.  
  4114.  
  4115. ;******************************************************************************
  4116. ; Event handler for threshold events.
  4117. pro Viz3D_ThreshEvent, event
  4118.  
  4119.    WIDGET_CONTROL, event.id, GET_UVALUE=uVal
  4120.    if (uVal ne 'wThreshDraw') then WIDGET_CONTROL, /HOURGLASS
  4121.  
  4122.    if (uVal eq 'wMainDraw') then begin
  4123.       wDrawBase = WIDGET_INFO(event.id, /PARENT)
  4124.       WIDGET_CONTROL, wDrawBase, GET_UVALUE=wMainBase
  4125.    endif else wMainBase = event.top
  4126.  
  4127.    WIDGET_CONTROL, wMainBase, GET_UVALUE=sMainState, /NO_COPY
  4128.  
  4129.    HANDLE_VALUE, sMainState.sThreshState.hLowThresh, lowThresh, /NO_COPY
  4130.    HANDLE_VALUE, sMainState.sThreshState.hHighThresh, highThresh, /NO_COPY
  4131.    HANDLE_VALUE, sMainState.sThreshState.hTransVal, transVal, /NO_COPY
  4132.    lTh = lowThresh(sMainState.curData)
  4133.    hTh = highThresh(sMainState.curData)
  4134.    vTp = transVal(sMainState.curData)
  4135.    HANDLE_VALUE, sMainState.sThreshState.hLowThresh, lowThresh, /NO_COPY, /SET
  4136.    HANDLE_VALUE, sMainState.sThreshState.hHighThresh, highThresh, $
  4137.       /NO_COPY, /SET
  4138.    HANDLE_VALUE, sMainState.sThreshState.hTransVal, transVal, /NO_COPY, /SET
  4139.  
  4140.    HANDLE_VALUE, sMainState.sThreshState.hMinData, minData, /NO_COPY
  4141.    HANDLE_VALUE, sMainState.sThreshState.hMaxData, maxData, /NO_COPY
  4142.    minD = minData(sMainState.curData)
  4143.    maxD = maxData(sMainState.curData)
  4144.    HANDLE_VALUE, sMainState.sThreshState.hMinData, minData, /NO_COPY, /SET
  4145.    HANDLE_VALUE, sMainState.sThreshState.hMaxData, maxData, /NO_COPY, /SET
  4146.  
  4147.    case uVal of
  4148.       'wMainDraw': ; Big draw window, do nothing.
  4149.       'wThreshDraw': begin ; Set new threshold value via draw widget.
  4150.          if (event.release le 0) then begin
  4151.             if (event.press eq 1) then sMainState.sThreshState.moveType = 0
  4152.             if (event.press ge 2) then sMainState.sThreshState.moveType = 1
  4153.             if (sMainState.sThreshState.moveType eq 0) then begin
  4154.                ; Move high/low threshold
  4155.                ; Determine which to set, high or low.
  4156.                WSET, sMainState.sThreshState.threshWin
  4157.                norm = FLOAT(event.x) / FLOAT(!D.X_SIZE)
  4158.                norm = (norm - 0.03) / (0.97 - 0.03)
  4159.                newThresh = (norm * (maxD - minD)) + minD
  4160.                newThresh = (newThresh > minD) < maxD
  4161.  
  4162.                ; Closer to min threshold.
  4163.                if (ABS(newThresh - lTh) lt ABS(newThresh - hTh)) then begin
  4164.                   newThresh = newThresh < hTh
  4165.                   HANDLE_VALUE, sMainState.sThreshState.hLowThresh, $
  4166.                      lowThresh, /NO_COPY
  4167.                   lowThresh(sMainState.curData) = newThresh
  4168.                   HANDLE_VALUE, sMainState.sThreshState.hLowThresh, $
  4169.                      lowThresh, /NO_COPY, /SET
  4170.                endif 
  4171.                ; Closer to max threshold.
  4172.                if (ABS(newThresh - lTh) gt ABS(newThresh - hTh)) then begin
  4173.                   newThresh = newThresh > lTh
  4174.                   HANDLE_VALUE, sMainState.sThreshState.hHighThresh, $
  4175.                      highThresh, /NO_COPY
  4176.                   highThresh(sMainState.curData) = newThresh
  4177.                   HANDLE_VALUE, sMainState.sThreshState.hHighThresh, $
  4178.                      highThresh, /NO_COPY, /SET
  4179.                endif
  4180.                if (ABS(newThresh - lTh) eq ABS(newThresh - hTh)) then begin
  4181.                   newThresh = (newThresh > minD) < maxD
  4182.                   if (newThresh gt hTh) then begin
  4183.                      HANDLE_VALUE, sMainState.sThreshState.hHighThresh, $
  4184.                         highThresh, /NO_COPY
  4185.                      highThresh(sMainState.curData) = newThresh
  4186.                      HANDLE_VALUE, sMainState.sThreshState.hHighThresh, $
  4187.                         highThresh, /NO_COPY, /SET
  4188.                   endif
  4189.                   if (newThresh lt lTh) then begin
  4190.                      HANDLE_VALUE, sMainState.sThreshState.hLowThresh, $
  4191.                         lowThresh, /NO_COPY
  4192.                      lowThresh(sMainState.curData) = newThresh
  4193.                      HANDLE_VALUE, sMainState.sThreshState.hLowThresh, $
  4194.                         lowThresh, /NO_COPY, /SET
  4195.                   endif
  4196.                endif
  4197.  
  4198.                ; Make sure the min and max threshold values are not equal.
  4199.                HANDLE_VALUE, sMainState.sThreshState.hLowThresh, $
  4200.                   lowThresh, /NO_COPY
  4201.                HANDLE_VALUE, sMainState.sThreshState.hHighThresh, $
  4202.                   highThresh, /NO_COPY
  4203.                if (lowThresh(sMainState.curData) eq $
  4204.                    highThresh(sMainState.curData)) then begin
  4205.                   lowThresh(sMainState.curData) = minD
  4206.                   highThresh(sMainState.curData) = maxD
  4207.                endif
  4208.                HANDLE_VALUE, sMainState.sThreshState.hLowThresh, $
  4209.                   lowThresh, /NO_COPY, /SET
  4210.                HANDLE_VALUE, sMainState.sThreshState.hHighThresh, $
  4211.                   highThresh, /NO_COPY, /SET
  4212.  
  4213.             endif else begin ; Move transparency.
  4214.                WSET, sMainState.sThreshState.threshWin
  4215.                norm = FLOAT(event.x) / FLOAT(!D.X_SIZE)
  4216.                norm = (norm - 0.03) / (0.97 - 0.03)
  4217.                newThresh = (norm * (maxD - minD)) + minD
  4218.                newThresh = (newThresh > minD) < maxD
  4219.  
  4220.                HANDLE_VALUE, sMainState.sThreshState.hTransVal, transVal, $
  4221.                   /NO_COPY
  4222.                transVal(sMainState.curData) = newThresh
  4223.                HANDLE_VALUE, sMainState.sThreshState.hTransVal, transVal, $
  4224.                   /NO_COPY, /SET
  4225.             endelse
  4226.  
  4227.             WIDGET_CONTROL, event.id, /DRAW_MOTION_EVENTS, $
  4228.                /DRAW_BUTTON_EVENTS
  4229.             WSET, sMainState.mainWin
  4230.          endif else begin
  4231.             WIDGET_CONTROL, event.id, DRAW_MOTION_EVENTS=0, $
  4232.                /DRAW_BUTTON_EVENTS
  4233.             WIDGET_CONTROL, /HOURGLASS
  4234.             if (event.release eq 1) then begin
  4235.                WIDGET_CONTROL, /HOURGLASS
  4236.                Viz3D_SurfShow, sMainState, /CALC_HIST
  4237.             endif
  4238.          endelse
  4239.  
  4240.          Viz3D_ThreshShow, sMainState, /DYNAMIC
  4241.       end
  4242.       'wThreshLowText': begin
  4243.          WIDGET_CONTROL, event.id, GET_VALUE=newThresh
  4244.          newThresh = FLOAT(newThresh(0))
  4245.          newThresh = (newThresh > minD) < hTh
  4246.  
  4247.          HANDLE_VALUE, sMainState.sThreshState.hLowThresh, lowThresh, $
  4248.             /NO_COPY
  4249.          HANDLE_VALUE, sMainState.sThreshState.hHighThresh, highThresh, $
  4250.             /NO_COPY
  4251.          lowThresh(sMainState.curData) = newThresh
  4252.          if (lowThresh(sMainState.curData) eq $
  4253.              highThresh(sMainState.curData)) then begin
  4254.             lowThresh(sMainState.curData) = minD
  4255.             highThresh(sMainState.curData) = maxD
  4256.          endif
  4257.          HANDLE_VALUE, sMainState.sThreshState.hLowThresh, lowThresh, $
  4258.             /NO_COPY, /SET
  4259.          HANDLE_VALUE, sMainState.sThreshState.hHighThresh, highThresh, $
  4260.             /NO_COPY, /SET
  4261.  
  4262.          WIDGET_CONTROL, event.id, SET_VALUE=STRTRIM(STRING(newThresh),2)
  4263.          Viz3D_ThreshShow, sMainState, /DYNAMIC
  4264.          Viz3D_SurfShow, sMainState, /CALC_HIST
  4265.       end
  4266.       'wThreshHighText': begin
  4267.          WIDGET_CONTROL, event.id, GET_VALUE=newThresh
  4268.          newThresh = FLOAT(newThresh(0))
  4269.          newThresh = (newThresh > lTh) < maxD
  4270.  
  4271.          HANDLE_VALUE, sMainState.sThreshState.hLowThresh, lowThresh, $
  4272.             /NO_COPY
  4273.          HANDLE_VALUE, sMainState.sThreshState.hHighThresh, highThresh, $
  4274.             /NO_COPY
  4275.          highThresh(sMainState.curData) = newThresh
  4276.          if (lowThresh(sMainState.curData) eq $
  4277.              highThresh(sMainState.curData)) then begin
  4278.             lowThresh(sMainState.curData) = minD
  4279.             highThresh(sMainState.curData) = maxD
  4280.          endif
  4281.          HANDLE_VALUE, sMainState.sThreshState.hHighThresh, highThresh, $
  4282.             /NO_COPY, /SET
  4283.          HANDLE_VALUE, sMainState.sThreshState.hLowThresh, lowThresh, $
  4284.             /NO_COPY, /SET
  4285.  
  4286.          WIDGET_CONTROL, event.id, SET_VALUE=STRTRIM(STRING(newThresh),2)
  4287.          Viz3D_ThreshShow, sMainState, /DYNAMIC
  4288.          Viz3D_SurfShow, sMainState, /CALC_HIST
  4289.       end
  4290.       'wThreshTransText': begin
  4291.          WIDGET_CONTROL, event.id, GET_VALUE=newThresh
  4292.          newThresh = FLOAT(newThresh(0))
  4293.          newThresh = (newThresh > minD) < maxD
  4294.  
  4295.          HANDLE_VALUE, sMainState.sThreshState.hTransVal, transVal, $
  4296.             /NO_COPY
  4297.          transVal(sMainState.curData) = newThresh
  4298.          HANDLE_VALUE, sMainState.sThreshState.hTransVal, transVal, $
  4299.             /NO_COPY, /SET
  4300.  
  4301.          WIDGET_CONTROL, event.id, SET_VALUE=STRTRIM(STRING(newThresh),2)
  4302.          Viz3D_ThreshShow, sMainState, /DYNAMIC
  4303.       end
  4304.    endcase
  4305.  
  4306.    WIDGET_CONTROL, wMainBase, SET_UVALUE=sMainState, /NO_COPY
  4307. end
  4308. ;******************************************************************************
  4309.  
  4310.  
  4311. ;******************************************************************************
  4312. ; Event handler for profile events.
  4313. pro Viz3D_ProfileEvent, event
  4314.  
  4315.    WIDGET_CONTROL, event.id, GET_UVALUE=uVal
  4316.    if (uVal eq 'wMainDraw') then begin
  4317.       wDrawBase = WIDGET_INFO(event.id, /PARENT)
  4318.       WIDGET_CONTROL, wDrawBase, GET_UVALUE=wMainBase
  4319.    endif else begin
  4320.       wMainBase = event.top
  4321.       WIDGET_CONTROL, /HOURGLASS
  4322.    endelse
  4323.  
  4324.    WIDGET_CONTROL, wMainBase, GET_UVALUE=sMainState, /NO_COPY
  4325.  
  4326.    case uVal of
  4327.       'wProfDraw': ; Profile window, do nothing.
  4328.       'wMainDraw': begin ; Big draw window.
  4329.          if (event.release ge 1) then begin
  4330.             WIDGET_CONTROL, sMainState.wMainDraw, DRAW_MOTION_EVENTS=0, $
  4331.                /DRAW_BUTTON_EVENTS
  4332.             WIDGET_CONTROL, /HOURGLASS
  4333.          endif
  4334.  
  4335.          if ((event.press ge 1) or $
  4336.             ((event.press eq 0) and (event.release eq 0))) then begin
  4337.  
  4338.             if (event.press ge 1) then begin
  4339.                ; Initiate dynamic profile positioning.
  4340.                WIDGET_CONTROL, sMainState.wMainDraw, /DRAW_MOTION_EVENTS, $
  4341.                   /DRAW_BUTTON_EVENTS
  4342.                sMainState.cleanupView = 1
  4343.             endif
  4344.             if (event.press eq 1) then $
  4345.                sMainState.sProfState.frontBack = 1
  4346.             if (event.press gt 1) then $
  4347.                sMainState.sProfState.frontBack = 0
  4348.  
  4349.             ; Compute a 3D cube surface location from the current
  4350.             ; cursor position.
  4351.             if (sMainState.sProfState.frontBack) then $
  4352.                xyzPos = Viz3D_XYZPos(event.x, event.y, $
  4353.                   sMainState.hFrontDepth, sMainState.hFrontImage, $
  4354.                   sMainState.sViewState.invTrans, ON_FACE=onFace) $
  4355.             else $
  4356.                xyzPos = Viz3D_XYZPos(event.x, event.y, $
  4357.                   sMainState.hBackDepth, sMainState.hBackImage, $
  4358.                   sMainState.sViewState.invTrans, ON_FACE=onFace)
  4359.  
  4360.             xyzPos = ROUND(xyzPOS)
  4361.  
  4362.             if (onFace gt 0) then begin ; On cube, draw profile.
  4363.                if (sMainState.sProfState.profType eq 0) then begin
  4364.                   ; Orthogonal profile.
  4365.                   sMainState.sProfState.profDir = onFace
  4366.                   case onFace of
  4367.                      1: begin
  4368.                         sMainState.sProfState.x1Ortho = xyzPos(0)
  4369.                         sMainState.sProfState.x2Ortho = xyzPos(0)
  4370.                         sMainState.sProfState.y1Ortho = xyzPos(1)
  4371.                         sMainState.sProfState.y2Ortho = xyzPos(1)
  4372.                         sMainState.sProfState.z1Ortho = 0
  4373.                         sMainState.sProfState.z2Ortho = $
  4374.                            sMainState.szData(3) - 1
  4375.                      end
  4376.                      2: begin
  4377.                         sMainState.sProfState.x1Ortho = xyzPos(0)
  4378.                         sMainState.sProfState.x2Ortho = xyzPos(0)
  4379.                         sMainState.sProfState.y1Ortho = 0
  4380.                         sMainState.sProfState.y2Ortho = $
  4381.                            sMainState.szData(2) - 1
  4382.                         sMainState.sProfState.z1Ortho = xyzPos(2)
  4383.                         sMainState.sProfState.z2Ortho = xyzPos(2)
  4384.                      end
  4385.                      3: begin
  4386.                         sMainState.sProfState.x1Ortho = 0
  4387.                         sMainState.sProfState.x2Ortho = $
  4388.                            sMainState.szData(1) - 1
  4389.                         sMainState.sProfState.y1Ortho = xyzPos(1)
  4390.                         sMainState.sProfState.y2Ortho = xyzPos(1)
  4391.                         sMainState.sProfState.z1Ortho = xyzPos(2)
  4392.                         sMainState.sProfState.z2Ortho = xyzPos(2)
  4393.                      end
  4394.                   endcase
  4395.                endif else begin ; Oblique profile.
  4396.                   if (sMainState.sProfState.frontBack) then begin
  4397.                      sMainState.sProfState.x1Obliq = xyzPos(0)
  4398.                      sMainState.sProfState.y1Obliq = xyzPos(1)
  4399.                      sMainState.sProfState.z1Obliq = xyzPos(2)
  4400.                   endif else begin
  4401.                      sMainState.sProfState.x2Obliq = xyzPos(0)
  4402.                      sMainState.sProfState.y2Obliq = xyzPos(1)
  4403.                      sMainState.sProfState.z2Obliq = xyzPos(2)
  4404.                   endelse
  4405.                endelse
  4406.  
  4407.                if (onFace ne sMainState.sProfState.onFace) then begin
  4408.                   sMainState.sProfState.onFace = onFace
  4409.                   Viz3D_ProfShow, sMainState
  4410.                endif else Viz3D_ProfShow, sMainState, /DIRECT
  4411.  
  4412.                Viz3D_ProfDraw, sMainState
  4413.  
  4414.             endif
  4415.          endif
  4416.       end
  4417.       'wProfOrthoBttn': begin
  4418.          sMainState.sProfState.profType = 0
  4419.          Viz3D_ProfShow, sMainState
  4420.          Viz3D_ProfDraw, sMainState
  4421.       end
  4422.       'wProfObliqBttn': begin
  4423.          sMainState.sProfState.profType = 1
  4424.          Viz3D_ProfShow, sMainState
  4425.          Viz3D_ProfDraw, sMainState
  4426.       end
  4427.    endcase
  4428.  
  4429.    WIDGET_CONTROL, wMainBase, SET_UVALUE=sMainState, /NO_COPY
  4430. end
  4431. ;******************************************************************************
  4432.  
  4433.  
  4434. ;******************************************************************************
  4435. ; Event handler for probe events.
  4436. pro Viz3D_ProbeEvent, event
  4437.  
  4438.    WIDGET_CONTROL, event.id, GET_UVALUE=uVal
  4439.    if (uVal eq 'wMainDraw') then begin
  4440.       wDrawBase = WIDGET_INFO(event.id, /PARENT)
  4441.       WIDGET_CONTROL, wDrawBase, GET_UVALUE=wMainBase
  4442.    endif else begin
  4443.       wMainBase = event.top
  4444.       WIDGET_CONTROL, /HOURGLASS
  4445.    endelse
  4446.  
  4447.    WIDGET_CONTROL, wMainBase, GET_UVALUE=sMainState, /NO_COPY
  4448.  
  4449.    case uVal of
  4450.       'wMainDraw': begin ; Big draw window.
  4451.          if (event.release ge 1) then begin
  4452.             WIDGET_CONTROL, sMainState.wMainDraw, DRAW_MOTION_EVENTS=0, $
  4453.                /DRAW_BUTTON_EVENTS
  4454.             WIDGET_CONTROL, /HOURGLASS
  4455.          endif
  4456.  
  4457.          if (event.press ge 1) then $
  4458.             WIDGET_CONTROL, sMainState.wMainDraw, /DRAW_MOTION_EVENTS, $
  4459.                /DRAW_BUTTON_EVENTS
  4460.  
  4461.          if ((event.press ge 1) or $
  4462.             ((event.press eq 0) and (event.release eq 0))) then begin
  4463.  
  4464.             eX = (event.x > 0) < (!D.X_Size - 1)
  4465.             eY = (event.y > 0) < (!D.Y_Size - 1)
  4466.             nX = Float(eX) / Float(!D.X_Size - 1)
  4467.             nY = Float(eY) / Float(!D.Y_Size - 1)
  4468.             SET_PLOT, 'Z'
  4469.             nZ = (TVRD(eX, eY, 1, 1, CHANNEL=1, /WORDS))(0)
  4470.             SET_PLOT, sMainState.screenDevice
  4471.  
  4472.             HANDLE_VALUE, sMainState.hBackDepth, backDepth, /NO_COPY
  4473.             zBack = (backDepth(eX, eY))(0)
  4474.             HANDLE_VALUE, sMainState.hBackDepth, backDepth, /NO_COPY, /SET
  4475.  
  4476.             HANDLE_VALUE, sMainState.hfrontDepth, frontDepth, /NO_COPY
  4477.             zFront = (frontDepth(eX, eY))(0)
  4478.             HANDLE_VALUE, sMainState.hfrontDepth, frontDepth, /NO_COPY, /SET
  4479.  
  4480.             if (zFront gt (-32765)) then begin
  4481.  
  4482.                if (nZ gt zBack) then begin
  4483.                   nZ = (FLOAT(nZ) + 32765.0) / (2.0 * 32765.0)
  4484.  
  4485.                   xyzNorm = [nX, nY, nZ, 1.0] # sMainState.sViewState.invTrans
  4486.                   xyzNorm = xyzNorm / xyzNorm(3)
  4487.  
  4488.                   xPos = (((xyzNorm(0) - !X.S(0)) / !X.S(1)) > 0.0) < $
  4489.                      FLOAT(sMainState.szData(1)-1)
  4490.                   yPos = (((xyzNorm(1) - !Y.S(0)) / !Y.S(1)) > 0.0) < $
  4491.                      FLOAT(sMainState.szData(2)-1)
  4492.                   zPos = (((xyzNorm(2) - !Z.S(0)) / !Z.S(1)) > 0.0) < $
  4493.                      FLOAT(sMainState.szData(3)-1)
  4494.  
  4495.                   sMainState.sProbeState.x = xPos
  4496.                   sMainState.sProbeState.y = yPos
  4497.                   sMainState.sProbeState.z = zPos
  4498.  
  4499.                   Viz3D_ProbeDraw, sMainState
  4500.  
  4501.                endif else begin
  4502.                   WIDGET_CONTROL, sMainState.wStatText, $
  4503.                      SET_VALUE=('No data value')
  4504.                   WSET, sMainState.mainWin
  4505.                   DEVICE, COPY=[0, 0, sMainState.winX, sMainState.winY, $
  4506.                                 0, 0, sMainState.pixWin]
  4507.                   WIDGET_CONTROL, sMainState.sProbeState.wProbeXText, $
  4508.                      SET_VALUE=''
  4509.                   WIDGET_CONTROL, sMainState.sProbeState.wProbeYText, $
  4510.                      SET_VALUE=''
  4511.                   WIDGET_CONTROL, sMainState.sProbeState.wProbeZText, $
  4512.                      SET_VALUE=''
  4513.                endelse
  4514.             endif else begin
  4515.                WIDGET_CONTROL, sMainState.wStatText, $
  4516.                   SET_VALUE=('')
  4517.                WIDGET_CONTROL, sMainState.sProbeState.wProbeXText, $
  4518.                   SET_VALUE=''
  4519.                WIDGET_CONTROL, sMainState.sProbeState.wProbeYText, $
  4520.                   SET_VALUE=''
  4521.                WIDGET_CONTROL, sMainState.sProbeState.wProbeZText, $
  4522.                   SET_VALUE=''
  4523.                WSET, sMainState.mainWin
  4524.                DEVICE, COPY=[0, 0, sMainState.winX, sMainState.winY, $
  4525.                              0, 0, sMainState.pixWin]
  4526.             endelse
  4527.          endif
  4528.       end
  4529.       'wProbeText': begin
  4530.          WIDGET_CONTROL, sMainState.sProbeState.wProbeXText, GET_VALUE=xT
  4531.          WIDGET_CONTROL, sMainState.sProbeState.wProbeYText, GET_VALUE=yT
  4532.          WIDGET_CONTROL, sMainState.sProbeState.wProbeZText, GET_VALUE=zT
  4533.          sMainState.sProbeState.x = (FLOAT(xt(0)) > 0.0) < $
  4534.             FLOAT(sMainState.szData(1)-1)
  4535.          sMainState.sProbeState.y = (FLOAT(yt(0)) > 0.0) < $
  4536.             FLOAT(sMainState.szData(2)-1)
  4537.          sMainState.sProbeState.z = (FLOAT(zt(0)) > 0.0) < $
  4538.             FLOAT(sMainState.szData(3)-1)
  4539.          xT = STRTRIM(STRING(sMainState.sProbeState.x), 2)
  4540.          yT = STRTRIM(STRING(sMainState.sProbeState.y), 2)
  4541.          zT = STRTRIM(STRING(sMainState.sProbeState.z), 2)
  4542.          WIDGET_CONTROL, sMainState.sProbeState.wProbeXText, SET_VALUE=xT
  4543.          WIDGET_CONTROL, sMainState.sProbeState.wProbeYText, SET_VALUE=yT
  4544.          WIDGET_CONTROL, sMainState.sProbeState.wProbeZText, SET_VALUE=zT
  4545.          Viz3D_ProbeDraw, sMainState
  4546.       end
  4547.    endcase
  4548.  
  4549.    WIDGET_CONTROL, wMainBase, SET_UVALUE=sMainState, /NO_COPY
  4550. end
  4551. ;******************************************************************************
  4552.  
  4553.  
  4554. ;******************************************************************************
  4555. ; Event handler for view events.
  4556. pro Viz3D_ViewEvent, event
  4557.    WIDGET_CONTROL, /HOURGLASS
  4558.  
  4559.    WIDGET_CONTROL, event.id, GET_UVALUE=uVal
  4560.    if (uVal eq 'wMainDraw') then begin
  4561.       wDrawBase = WIDGET_INFO(event.id, /PARENT)
  4562.       WIDGET_CONTROL, wDrawBase, GET_UVALUE=wMainBase
  4563.    endif else wMainBase = event.top
  4564.  
  4565.    WIDGET_CONTROL, wMainBase, GET_UVALUE=sMainState, /NO_COPY
  4566.  
  4567.    Viz3D_CleanView, sMainState, /SKIP_BUFFER
  4568.  
  4569.    redraw_flag = 0
  4570.    case uVal of
  4571.       'wMainDraw': ; Big draw window, do nothing.
  4572.       'wViewDraw': ; Small view window, do nothing.
  4573.       'wRot1Slid': begin
  4574.          if (sMainState.sViewState.ang1 ne event.value) then redraw_flag = 1
  4575.          sMainState.sViewState.ang1 = event.value
  4576.       end
  4577.       'wRot2Slid': begin
  4578.          if (sMainState.sViewState.ang2 ne event.value) then redraw_flag = 1
  4579.          sMainState.sViewState.ang2 = event.value
  4580.       end
  4581.       'wRot3Slid': begin
  4582.          if (sMainState.sViewState.ang3 ne event.value) then redraw_flag = 1
  4583.          sMainState.sViewState.ang3 = event.value
  4584.       end
  4585.       'wRot1Drop': begin
  4586.          case event.index of
  4587.             0: rot_axis = 'X'
  4588.             1: rot_axis = 'Y'
  4589.             2: rot_axis = 'Z'
  4590.          endcase
  4591.          if (sMainState.sViewState.dir1 ne rot_axis) then redraw_flag = 1
  4592.          sMainState.sViewState.dir1 = rot_axis
  4593.       end
  4594.       'wRot2Drop': begin
  4595.          case event.index of
  4596.             0: rot_axis = 'X'
  4597.             1: rot_axis = 'Y'
  4598.             2: rot_axis = 'Z'
  4599.          endcase
  4600.          if (sMainState.sViewState.dir2 ne rot_axis) then redraw_flag = 1
  4601.          sMainState.sViewState.dir2 = rot_axis
  4602.       end
  4603.       'wRot3Drop': begin
  4604.          case event.index of
  4605.             0: rot_axis = 'X'
  4606.             1: rot_axis = 'Y'
  4607.             2: rot_axis = 'Z'
  4608.          endcase
  4609.          if (sMainState.sViewState.dir3 ne rot_axis) then redraw_flag = 1
  4610.          sMainState.sViewState.dir3 = rot_axis
  4611.       end
  4612.       'wZoomSlid': begin
  4613.          zoomVal = FLOAT(event.value) / 100.0
  4614.          if (sMainState.sViewState.zoomFac ne zoomVal) then redraw_flag = 1
  4615.          sMainState.sViewState.zoomFac = zoomVal
  4616.       end
  4617.       'wZFacSlid': begin
  4618.          zFac = FLOAT(event.value) / 100.0
  4619.          if (sMainState.sViewState.zScale ne zFac) then redraw_flag = 1
  4620.          sMainState.sViewState.zScale = zFac
  4621.       end
  4622.       'wPerspSlid': begin
  4623.          perspDist = FLOAT(event.value)
  4624.          if (sMainState.sViewState.pDist ne perspDist) then redraw_flag = 1
  4625.          sMainState.sViewState.pDist = perspDist
  4626.       end
  4627.       'wViewDispBttn': begin
  4628.          sMainState.cleanupBuffer = 1
  4629.          Viz3D_CleanBuffer, sMainState
  4630.       end
  4631.    endcase
  4632.  
  4633.    if (redraw_flag) then begin
  4634.       sMainState.sViewState = $
  4635.          Viz3D_View(sMainState.sViewState.viewWin, $
  4636.             XMAX=sMainState.sViewState.xMax, $
  4637.             YMAX=sMainState.sViewState.yMax, $
  4638.             ZMAX=sMainState.sViewState.zMax, $
  4639.             ANG1=sMainState.sViewState.ang1, $
  4640.             ANG2=sMainState.sViewState.ang2, $
  4641.             ANG3=sMainState.sViewState.ang3, $
  4642.             DIR1=sMainState.sViewState.dir1, $
  4643.             DIR2=sMainState.sViewState.dir2, $
  4644.             DIR3=sMainState.sViewState.dir3, $
  4645.             ZOOM=sMainState.sViewState.zoomFac , $
  4646.             ZSCALE=sMainState.sViewState.zScale , $
  4647.             PERSP=sMainState.sViewState.pDist)
  4648.       Viz3D_ViewShow, sMainState
  4649.       sMainState.cleanupBuffer = 1
  4650.    endif
  4651.  
  4652.    WIDGET_CONTROL, wMainBase, SET_UVALUE=sMainState, /NO_COPY
  4653. end
  4654. ;******************************************************************************
  4655.  
  4656.  
  4657. ;******************************************************************************
  4658. ; Differential shading event handler.
  4659. pro Viz3D_DiffShadeEvent, event
  4660.    WIDGET_CONTROL, /HOURGLASS
  4661.  
  4662.    WIDGET_CONTROL, event.id, GET_UVALUE=uVal
  4663.  
  4664.    case uVal of
  4665.       'wDiffSlid': begin
  4666.          WIDGET_CONTROL, event.top, GET_UVALUE=leader
  4667.          WIDGET_CONTROL, leader, GET_UVALUE=sMainState, /NO_COPY
  4668.          sMainState.sColorState.diffShade = event.value
  4669.          sViz3DColors = sMainState.sColorState
  4670.          Viz3D_DiffColor, sViz3DColors
  4671.          sMainState.sColorState = TEMPORARY(sViz3DColors)
  4672.  
  4673.          if (event.drag eq 0) then begin
  4674.             WSET, sMainState.mainWin
  4675.             DEVICE, COPY=[0, 0, sMainState.winX, sMainState.winY, 0, 0, $
  4676.                           sMainState.pixWin]
  4677.          endif
  4678.  
  4679.          WIDGET_CONTROL, leader, SET_UVALUE=sMainState, /NO_COPY
  4680.       end
  4681.       'wDiffCloseBttn': WIDGET_CONTROL, event.top, /DESTROY
  4682.    endcase
  4683. end
  4684. ;******************************************************************************
  4685.  
  4686.  
  4687. ;******************************************************************************
  4688. ; Options event handler.
  4689. pro Viz3D_OptEvent, event
  4690.    WIDGET_CONTROL, /HOURGLASS
  4691.  
  4692.    WIDGET_CONTROL, event.id, GET_UVALUE=uVal
  4693.    WIDGET_CONTROL, event.top, GET_UVALUE=hState
  4694.    HANDLE_VALUE, hState, sOptState, /NO_COPY
  4695.  
  4696.    WIDGET_CONTROL, sOptState.wOptSizeText, GET_VALUE=szText
  4697.    DEVICE, GET_SCREEN_SIZE=scrSize
  4698.    wSize = (FIX(szText(0)) > 256) < (scrSize(1) - 80)
  4699.    WIDGET_CONTROL, sOptState.wOptSizeText, SET_VALUE=STRING(wSize)
  4700.    sOptState.winXY = wSize
  4701.  
  4702.    case uVal of
  4703.       'wOptAxisOnBttn': sOptState.AxisOn = 1
  4704.       'wOptAxisOffBttn': sOptState.AxisOn = 0
  4705.       'wOptCubeOnBttn': sOptState.CubeOn = 1
  4706.       'wOptCubeOffBttn': sOptState.CubeOn = 0
  4707.       'wOptSizeText':
  4708.       'wOptOkBttn': begin
  4709.          sOptState.Ok = 1
  4710.          WIDGET_CONTROL, event.top, /DESTROY
  4711.       end
  4712.       'wOptCanBttn': begin
  4713.          sOptState.Ok = 0
  4714.          WIDGET_CONTROL, event.top, /DESTROY
  4715.       end
  4716.    endcase
  4717.  
  4718.    HANDLE_VALUE, hState, sOptState, /NO_COPY, /SET
  4719. end
  4720. ;******************************************************************************
  4721.  
  4722.  
  4723. ;******************************************************************************
  4724. ; Main event handler.
  4725. pro Viz3D_Event, event
  4726.  
  4727. ON_IOERROR, IO_BAD
  4728.  
  4729.    WIDGET_CONTROL, /HOURGLASS
  4730.  
  4731.    WIDGET_CONTROL, event.id, GET_UVALUE=uVal
  4732.    if (uVal eq 'wMainDraw') then begin
  4733.       wDrawBase = WIDGET_INFO(event.id, /PARENT)
  4734.       WIDGET_CONTROL, wDrawBase, GET_UVALUE=mainID
  4735.    endif else mainID = event.top
  4736.  
  4737.    WIDGET_CONTROL, mainID, GET_UVALUE=sMainState, /NO_COPY
  4738.  
  4739.    if ((uVal ne 'wQuitBttn') AND (uVal ne 'wDelAllBttn')) then $
  4740.       Viz3D_CleanView, sMainState
  4741.  
  4742.    case uVal of
  4743.       'wQuitBttn': begin ; Exit.
  4744.          WIDGET_CONTROL, mainID, SET_UVALUE=sMainState, /NO_COPY
  4745.          WIDGET_CONTROL, mainID, /Destroy
  4746.          return
  4747.       end
  4748.  
  4749.       'wLoadBttn': begin ; Load new data from a file.
  4750.          ; Get file name.
  4751.          dataFile = PICKFILE(GROUP=event.top, /READ, FILTER='*.dat', $
  4752.                              /MUST_EXIST)
  4753.          WIDGET_CONTROL, /HOURGLASS
  4754.          if (dataFile(0) eq '') then begin ; No file, user cancelled.
  4755.             WIDGET_CONTROL, mainID, SET_UVALUE=sMainState, /NO_COPY
  4756.             return
  4757.          endif
  4758.  
  4759.          ; Open file.
  4760.          GET_LUN, lun
  4761.          OPENR, lun, dataFile
  4762.  
  4763.          ; Read in and check the data.
  4764.  
  4765.          goRead = 1
  4766.          count = 0
  4767.  
  4768.          ; Keep reading as long as there is valid data.
  4769.          while (goRead) do begin
  4770.             count = count + 1
  4771.  
  4772.             fileStat = FSTAT(lun)
  4773.  
  4774.             if (fileStat.cur_ptr eq fileStat.size) then begin ; At EOF.
  4775.                WIDGET_CONTROL, mainID, SET_UVALUE=sMainState, /NO_COPY
  4776.                CLOSE, lun
  4777.                FREE_LUN, lun
  4778.                return
  4779.             endif
  4780.  
  4781.             if ((fileStat.size - fileStat.cur_ptr) lt 29L) then begin
  4782.                ; Not enough bytes in file for data "header".
  4783.                ans = WIDGET_MESSAGE( $
  4784.                   'File does not contain valid 3-D data.', /ERROR)
  4785.                WIDGET_CONTROL, mainID, SET_UVALUE=sMainState, /NO_COPY
  4786.                CLOSE, lun
  4787.                FREE_LUN, lun
  4788.                return
  4789.             endif
  4790.  
  4791.             ; Read and check the number of dimensions.
  4792.             nDims = 0L
  4793.             READU, lun, nDims
  4794.             if ((ndims NE 3L) and (count eq 1)) then begin
  4795.                nDims = SWAP_ENDIAN(TEMPORARY(nDims))
  4796.                if (ndims NE 3L) then begin
  4797.                   ans = WIDGET_MESSAGE( $
  4798.                      'File does not contain valid 3-D data.', /ERROR)
  4799.                   WIDGET_CONTROL, mainID, SET_UVALUE=sMainState, /NO_COPY
  4800.                   CLOSE, lun
  4801.                   FREE_LUN, lun
  4802.                   return
  4803.                endif
  4804.                swapData = 1
  4805.             endif else swapData = 0
  4806.             if ((ndims NE 3L) and (count gt 1)) then begin
  4807.                ans = WIDGET_MESSAGE( $
  4808.                   'File does not contain valid 3-D data.', /ERROR)
  4809.                WIDGET_CONTROL, mainID, SET_UVALUE=sMainState, /NO_COPY
  4810.                CLOSE, lun
  4811.                FREE_LUN, lun
  4812.                return
  4813.             endif
  4814.  
  4815.             ; Read the rest of the data "size" info.
  4816.             sizeDims = LONARR(3, /NOZERO)
  4817.             READU, lun, sizeDims
  4818.             dataType = 0L
  4819.             READU, lun, dataType
  4820.             nElems = 0L
  4821.             READU, lun, nElems
  4822.  
  4823.             ; Read the number of characters in data name.
  4824.             nNameChars = 0L
  4825.             READU, lun, nNameChars
  4826.  
  4827.             ; Byte swap if necessary.
  4828.             if (swapData) then begin
  4829.                sizeDims = SWAP_ENDIAN(TEMPORARY(sizeDims))
  4830.                dataType = SWAP_ENDIAN(TEMPORARY(dataType))
  4831.                nElems = SWAP_ENDIAN(TEMPORARY(nElems))
  4832.                nNameChars = SWAP_ENDIAN(TEMPORARY(nNameChars))
  4833.             endif
  4834.  
  4835.             ; Check the size of the data dimensions.
  4836.             if (MIN(sizeDims) LE 1L) then begin
  4837.                ans = WIDGET_MESSAGE( $
  4838.                   'File does not contain valid 3-D data.', /ERROR)
  4839.                WIDGET_CONTROL, mainID, SET_UVALUE=sMainState, /NO_COPY
  4840.                CLOSE, lun
  4841.                FREE_LUN, lun
  4842.                return
  4843.             endif
  4844.  
  4845.             ; Check the data type.
  4846.             if ((dataType LT 1L) OR (dataType GT 5)) then begin
  4847.                ans = WIDGET_MESSAGE( $
  4848.                   'File does not contain valid 3-D data.', /ERROR)
  4849.                WIDGET_CONTROL, mainID, SET_UVALUE=sMainState, /NO_COPY
  4850.                CLOSE, lun
  4851.                FREE_LUN, lun
  4852.                return
  4853.             endif
  4854.  
  4855.             ; Check the number of elements.
  4856.             if ((sizeDims(0)*sizeDims(1)*sizeDims(2)) NE nElems) then begin
  4857.                ans = WIDGET_MESSAGE( $
  4858.                   'File does not contain valid 3-D data.', /ERROR)
  4859.                WIDGET_CONTROL, mainID, SET_UVALUE=sMainState, /NO_COPY
  4860.                CLOSE, lun
  4861.                FREE_LUN, lun
  4862.                return
  4863.             endif
  4864.  
  4865.             ; Check the number of characters in data name.
  4866.             if (nNameChars LT 1L) then begin
  4867.                ans = WIDGET_MESSAGE( $
  4868.                   'File contains invalid 3-D data name.', /ERROR)
  4869.                WIDGET_CONTROL, mainID, SET_UVALUE=sMainState, /NO_COPY
  4870.                CLOSE, lun
  4871.                FREE_LUN, lun
  4872.                return
  4873.             endif
  4874.  
  4875.             ; See if there is enough bytes left in the file for data name.
  4876.             fileStat = FSTAT(lun)
  4877.             if ((fileStat.size - fileStat.cur_ptr) LT nNameChars) then begin
  4878.                ans = WIDGET_MESSAGE( $
  4879.                   'File does not contain valid 3-D data.', /ERROR)
  4880.                WIDGET_CONTROL, mainID, SET_UVALUE=sMainState, /NO_COPY
  4881.                CLOSE, lun
  4882.                FREE_LUN, lun
  4883.                return
  4884.             endif
  4885.  
  4886.             ; Read the data name.
  4887.             dataName = BYTARR(nNameChars, /NOZERO)
  4888.             READU, lun, dataName
  4889.             dataName = STRING(dataName)
  4890.  
  4891.             case dataType of
  4892.                1: nBytes = nElems
  4893.                2: nBytes = nElems * 2L
  4894.                3: nBytes = nElems * 4L
  4895.                4: nBytes = nElems * 4L
  4896.                5: nBytes = nElems * 8L
  4897.             endcase
  4898.  
  4899.             fileStat = FSTAT(lun)
  4900.  
  4901.             ; If there are enough bytes left in the file, then read the data.
  4902.             if ((fileStat.size - fileStat.cur_ptr) ge nBytes) then begin
  4903.  
  4904.                if (count eq 1) then begin
  4905.                   ; Make the first data active.
  4906.                   sMainState.curData = 0
  4907.                   sMainState.sSurfState.curShade = 0
  4908.  
  4909.                   ; Something valid to read, so clean out the existing data.
  4910.                   HANDLE_VALUE, sMainState.hDataList, lData3D, /NO_COPY
  4911.                   for i=0, N_ELEMENTS(lData3D)-1L do begin
  4912.                      if (HANDLE_INFO(lData3D(i), /VALID_ID)) then $
  4913.                         HANDLE_FREE, lData3D(i)
  4914.                   endfor
  4915.                   HANDLE_VALUE, sMainState.sThreshState.hDataHist, $
  4916.                      lDataHist, /NO_COPY
  4917.                   for i=0, N_ELEMENTS(lDataHist)-1L do begin
  4918.                      if (HANDLE_INFO(lDataHist(i), /VALID_ID)) then $
  4919.                         HANDLE_FREE, lDataHist(i)
  4920.                   endfor
  4921.  
  4922.                   sizeDims1 = sizeDims
  4923.                endif else begin
  4924.                   ; Check if Nth data is the same size as the first data.
  4925.                   index = WHERE(sizeDims1 ne sizeDims)
  4926.                   if (index(0) ge 0L) then begin
  4927.                      ans = WIDGET_MESSAGE( $
  4928.                         'Data dimensions are not consistent.', /ERROR)
  4929.                      WIDGET_CONTROL, mainID, SET_UVALUE=sMainState, /NO_COPY
  4930.                      CLOSE, lun
  4931.                      FREE_LUN, lun
  4932.                      return
  4933.                   endif
  4934.                endelse
  4935.  
  4936.                ; Read the data.
  4937.                case dataType of
  4938.                   1: data3D = BYTARR(sizeDims(0), sizeDims(1), sizeDims(2), $
  4939.                                  /NOZERO)
  4940.                   2: data3D = INTARR(sizeDims(0), sizeDims(1), sizeDims(2), $
  4941.                                  /NOZERO)
  4942.                   3: data3D = LONARR(sizeDims(0), sizeDims(1), sizeDims(2), $
  4943.                                  /NOZERO)
  4944.                   4: data3D = FLTARR(sizeDims(0), sizeDims(1), sizeDims(2), $
  4945.                                  /NOZERO)
  4946.                   5: data3D = DBLARR(sizeDims(0), sizeDims(1), sizeDims(2), $
  4947.                                  /NOZERO)
  4948.                endcase
  4949.                READU, lun, data3D
  4950.                if (swapData) then data3D = SWAP_ENDIAN(TEMPORARY(data3D))
  4951.  
  4952.                if (count eq 1) then begin
  4953.  
  4954.                   ; First data, reset everything.
  4955.  
  4956.                   minData = MIN(data3D, MAX=maxData)
  4957.                   minData = DOUBLE(minData)
  4958.                   maxData = DOUBLE(maxData)
  4959.                   if (minData eq maxData) then maxData(0) = maxData(0) + 1.0D
  4960.                   bSize = (maxData - minData) / 200.0
  4961.                   dataHist = HISTOGRAM(FLOAT(data3D), $
  4962.                      MIN=minData, MAX=maxData, BINSIZE=bSize) > 1.0
  4963.                   dataHist = ALOG(FLOAT(TEMPORARY(dataHist))) > 0.0
  4964.  
  4965.                   lDataHist = HANDLE_CREATE(sMainState.hMain, $
  4966.                                  VALUE=dataHist)
  4967.                   lRangeHist = HANDLE_CREATE(sMainState.hMain, $
  4968.                                  VALUE=dataHist, /NO_COPY)
  4969.                   HANDLE_VALUE, sMainState.sThreshState.hDataHist, $
  4970.                      lDataHist, /NO_COPY, /SET
  4971.                   HANDLE_VALUE, sMainState.sSurfState.hRangeHist, $
  4972.                      lRangeHist, /NO_COPY, /SET
  4973.  
  4974.                   surfThresh = (minData + maxData) / 2.0D
  4975.                   HANDLE_VALUE, sMainState.sSurfState.hSurfThresh, $
  4976.                      surfThresh, /SET
  4977.  
  4978.                   szData = SIZE(data3D)
  4979.                   lData3D = HANDLE_CREATE(sMainState.hMain, $
  4980.                                VALUE=data3D, /NO_COPY)
  4981.                   HANDLE_VALUE, sMainState.hDataList, lData3D, /NO_COPY, /SET
  4982.  
  4983.                   WIDGET_CONTROL, sMainState.wDataModeBase, SENSITIVE=0
  4984.                   WIDGET_CONTROL, sMainState.sSurfState.wSurfShadeBase, $
  4985.                      SENSITIVE=0
  4986.                   WIDGET_CONTROL, sMainState.wDataDrop, $
  4987.                      SET_DROPLIST_SELECT=0, SET_VALUE=dataName(0)
  4988.                   WIDGET_CONTROL, sMainState.sSurfState.wSurfShadeDrop, $
  4989.                      SET_DROPLIST_SELECT=0, SET_VALUE='Light-source'
  4990.  
  4991.                   HANDLE_VALUE, sMainState.hDataName, dataName, /NO_COPY, /SET
  4992.                   HANDLE_VALUE, sMainState.sThreshState.hMinData, $
  4993.                      minData, /SET
  4994.                   HANDLE_VALUE, sMainState.sThreshState.hMaxData, $
  4995.                      maxData, /SET
  4996.                   HANDLE_VALUE, sMainState.sThreshState.hTransVal, $
  4997.                      minData, /SET
  4998.                   HANDLE_VALUE, sMainState.sThreshState.hLowThresh, $
  4999.                      minData, /NO_COPY, /SET
  5000.                   HANDLE_VALUE, sMainState.sThreshState.hHighThresh, $
  5001.                      maxData, /NO_COPY, /SET
  5002.  
  5003.                   sMainState.szData = szData
  5004.                   sMainState.sViewState = $
  5005.                      Viz3D_View(sMainState.sViewState.viewWin, $
  5006.                         XMAX=(szData(1)-1), $
  5007.                         YMAX=(szData(2)-1), $
  5008.                         ZMAX=(szData(3)-1), $
  5009.                         ANG1=sMainState.sViewState.ang1, $
  5010.                         ANG2=sMainState.sViewState.ang2, $
  5011.                         ANG3=sMainState.sViewState.ang3, $
  5012.                         DIR1=sMainState.sViewState.dir1, $
  5013.                         DIR2=sMainState.sViewState.dir2, $
  5014.                         DIR3=sMainState.sViewState.dir3, $
  5015.                         ZOOM=sMainState.sViewState.zoomFac , $
  5016.                         ZSCALE=sMainState.sViewState.zScale , $
  5017.                         PERSP=sMainState.sViewState.pDist)
  5018.  
  5019.                   sMainState.sBlockState.c1 = $
  5020.                      [szData(1)-1, szData(2)-1, szData(3)-1] / 3
  5021.                   sMainState.sBlockState.c2 = $
  5022.                      (2 * [szData(1)-1, szData(2)-1, szData(3)-1]) / 3
  5023.  
  5024.                   sMainState.sProfState.x1Ortho = FLOAT(szData(1) - 1L) / 2.0
  5025.                   sMainState.sProfState.y1Ortho = FLOAT(szData(2) - 1L) / 2.0
  5026.                   sMainState.sProfState.z1Ortho = 0.0
  5027.                   sMainState.sProfState.x2Ortho = FLOAT(szData(1) - 1L) / 2.0
  5028.                   sMainState.sProfState.y2Ortho = FLOAT(szData(2) - 1L) / 2.0
  5029.                   sMainState.sProfState.z2Ortho = FLOAT(szData(3) - 1L)
  5030.                   sMainState.sProfState.x1Obliq = FLOAT(szData(1) - 1L) / 2.0
  5031.                   sMainState.sProfState.y1Obliq = FLOAT(szData(2) - 1L) / 2.0
  5032.                   sMainState.sProfState.z1Obliq = 0.0
  5033.                   sMainState.sProfState.x2Obliq = FLOAT(szData(1) - 1L) / 2.0
  5034.                   sMainState.sProfState.y2Obliq = FLOAT(szData(2) - 1L) / 2.0
  5035.                   sMainState.sProfState.z2Obliq = FLOAT(szData(3) - 1L)
  5036.  
  5037.                   sMainState.sProbeState.x = FLOAT(szData(1) - 1L) / 2.0
  5038.                   sMainState.sProbeState.y = FLOAT(szData(2) - 1L) / 2.0
  5039.                   sMainState.sProbeState.z = FLOAT(szData(3) - 1L) / 2.0
  5040.  
  5041.                   ; Clean out the display list.
  5042.                   HANDLE_FREE, sMainState.hDisplayList
  5043.                   sMainState.hDisplayList = HANDLE_CREATE(sMainState.hMain)
  5044.                   ; Repair "Delete" menu.
  5045.                   delBttn = WIDGET_INFO(sMainState.wDeleteMenu, /CHILD)
  5046.                   WHILE (WIDGET_INFO(delBttn, /VALID_ID)) DO BEGIN
  5047.                      WIDGET_CONTROL, delBttn, /DESTROY
  5048.                      delBttn = WIDGET_INFO(sMainState.wDeleteMenu, /CHILD)
  5049.                   ENDWHILE
  5050.                   ; Erase.
  5051.                   SET_PLOT, 'Z'
  5052.                   ERASE
  5053.                   Viz3D_DrawData, sMainState
  5054.                   sMainState.cleanupBuffer = 1
  5055.                   Viz3D_ThreshShow, sMainState
  5056.                   Viz3D_SurfShow, sMainState, /CALC_HIST
  5057.                   Viz3D_CleanBuffer, sMainState
  5058.                   WIDGET_CONTROL, sMainState.wStatText, SET_VALUE=''
  5059.                   WIDGET_CONTROL, sMainState.sProbeState.wProbeXText, $
  5060.                      SET_VALUE=''
  5061.                   WIDGET_CONTROL, sMainState.sProbeState.wProbeYText, $
  5062.                      SET_VALUE=''
  5063.                   WIDGET_CONTROL, sMainState.sProbeState.wProbeZText, $
  5064.                      SET_VALUE=''
  5065.  
  5066.                endif else begin
  5067.  
  5068.                   ; Additional data.
  5069.  
  5070.                   minData = MIN(data3D, MAX=maxData)
  5071.                   minData = DOUBLE(minData)
  5072.                   maxData = DOUBLE(maxData)
  5073.                   if (minData eq maxData) then maxData(0) = maxData(0) + 1.0D
  5074.  
  5075.                   bSize = (maxData - minData) / 200.0
  5076.                   dataHist = HISTOGRAM(FLOAT(data3D), $
  5077.                      MIN=minData, MAX=maxData, BINSIZE=bSize) > 1.0
  5078.                   dataHist = ALOG(FLOAT(TEMPORARY(dataHist))) > 0.0
  5079.                   HANDLE_VALUE, sMainState.sThreshState.hDataHist, $
  5080.                      lDataHist, /NO_COPY
  5081.                   lDataHist = [TEMPORARY(lDataHist), $
  5082.                      HANDLE_CREATE(sMainState.hMain, VALUE=dataHist)]
  5083.                   HANDLE_VALUE, sMainState.sThreshState.hDataHist, $
  5084.                      lDataHist, /NO_COPY, /SET
  5085.                   HANDLE_VALUE, sMainState.sSurfState.hRangeHist, $
  5086.                      lRangeHist, /NO_COPY
  5087.                   lRangeHist = [TEMPORARY(lRangeHist), $
  5088.                      HANDLE_CREATE(sMainState.hMain, VALUE=dataHist, $
  5089.                      /NO_COPY)]
  5090.                   HANDLE_VALUE, sMainState.sSurfState.hRangeHist, $
  5091.                      lRangeHist, /NO_COPY, /SET
  5092.  
  5093.                   HANDLE_VALUE, sMainState.hDataList, lData3D, /NO_COPY
  5094.                   lData3D = [TEMPORARY(lData3D), $
  5095.                      HANDLE_CREATE(sMainState.hMain, VALUE=data3D, /NO_COPY)]
  5096.                   HANDLE_VALUE, sMainState.hDataList, lData3D, /NO_COPY, /SET
  5097.                   HANDLE_VALUE, sMainState.hDataName, dataNames, /NO_COPY
  5098.                   dataNames = [TEMPORARY(dataNames), dataName]
  5099.  
  5100.                   WIDGET_CONTROL, sMainState.wDataModeBase, SENSITIVE=1
  5101.                   WIDGET_CONTROL, sMainState.sSurfState.wSurfShadeBase, $
  5102.                      SENSITIVE=1
  5103.                   WIDGET_CONTROL, sMainState.wDataDrop, $
  5104.                      SET_DROPLIST_SELECT=0, SET_VALUE=dataNames
  5105.                   sName = dataNames
  5106.                   sName(0) = 'Light-source'
  5107.                   WIDGET_CONTROL, sMainState.sSurfState.wSurfShadeDrop, $
  5108.                      SET_DROPLIST_SELECT=0, SET_VALUE=sName
  5109.  
  5110.                   HANDLE_VALUE, sMainState.hDataName, dataNames, $
  5111.                      /NO_COPY, /SET
  5112.  
  5113.                   HANDLE_VALUE, sMainState.sThreshState.hMinData, lMinData, $
  5114.                      /NO_COPY
  5115.                   HANDLE_VALUE, sMainState.sThreshState.hMaxData, lMaxData, $
  5116.                      /NO_COPY
  5117.                   lMinData = [TEMPORARY(lMinData), minData]
  5118.                   lMaxData = [TEMPORARY(lMaxData), maxData]
  5119.  
  5120.                   surfThresh = (lMinData + lMaxData) / 2.0D
  5121.                   HANDLE_VALUE, sMainState.sSurfState.hSurfThresh, $
  5122.                      surfThresh, /NO_COPY, /SET
  5123.  
  5124.                   HANDLE_VALUE, sMainState.sThreshState.hTransVal, $
  5125.                      lMinData, /SET
  5126.                   HANDLE_VALUE, sMainState.sThreshState.hLowThresh, $
  5127.                      lMinData, /SET
  5128.                   HANDLE_VALUE, sMainState.sThreshState.hHighThresh, $
  5129.                      lMaxData, /SET
  5130.  
  5131.                   HANDLE_VALUE, sMainState.sThreshState.hMinData, lMinData, $
  5132.                      /NO_COPY, /SET
  5133.                   HANDLE_VALUE, sMainState.sThreshState.hMaxData, lMaxData, $
  5134.                      /NO_COPY, /SET
  5135.  
  5136.                endelse
  5137.             endif else begin
  5138.                goRead = 0
  5139.             endelse
  5140.  
  5141.          endwhile
  5142.  
  5143.          CLOSE, lun
  5144.          FREE_LUN, lun
  5145.  
  5146.       end
  5147.  
  5148.       'wSaveTiffBttn': begin ; Save tiff image.
  5149.          tiffFile = PICKFILE(GROUP=event.top, /WRITE, FILTER='*.tif', $
  5150.                              FILE='slicer3.tif')
  5151.          WIDGET_CONTROL, /HOURGLASS
  5152.          if (tiffFile(0) eq '') then begin
  5153.             WIDGET_CONTROL, mainID, SET_UVALUE=sMainState, /NO_COPY
  5154.             return
  5155.          endif
  5156.          tiffFiles = FINDFILE(tiffFile)
  5157.          if (tiffFiles(0) ne '') then begin
  5158.             ans = WIDGET_MESSAGE('File exists.   Overwrite ?', /QUESTION)
  5159.             WIDGET_CONTROL, /HOURGLASS
  5160.             if (ans ne 'Yes') then begin
  5161.                WIDGET_CONTROL, mainID, SET_UVALUE=sMainState, /NO_COPY
  5162.                return
  5163.             endif
  5164.          endif
  5165.          WSET, sMainState.pixWin
  5166.          if (sMainState.sColorState.displayBits eq 24) then begin
  5167.             iR = TVRD(CHANNEL=1)
  5168.             iG = TVRD(CHANNEL=2)
  5169.             iB = TVRD(CHANNEL=3)
  5170.  
  5171.             TIFF_WRITE, tiffFile(0), PLANARCONFIG=2, $
  5172.                RED=TEMPORARY(iR), GREEN=TEMPORARY(iG), BLUE=TEMPORARY(iB)
  5173.          endif else begin
  5174.             image = TVRD()
  5175.             TVLCT, cR, cG, cB, /GET
  5176.             TIFF_WRITE, tiffFile(0), TEMPORARY(image), $
  5177.                         RED=cR, GREEN=cG, BLUE=cB
  5178.          endelse
  5179.          WSET, sMAinState.mainWin
  5180.       end
  5181.  
  5182.       'wSaveSubsetBttn': begin ; Save subset.
  5183.          dataFile = PICKFILE(GROUP=event.top, /WRITE, FILTER='*.dat', $
  5184.                              FILE='slicer3.dat')
  5185.          WIDGET_CONTROL, /HOURGLASS
  5186.          if (dataFile(0) eq '') then begin
  5187.             WIDGET_CONTROL, mainID, SET_UVALUE=sMainState, /NO_COPY
  5188.             return
  5189.          endif
  5190.          dataFiles = FINDFILE(dataFile)
  5191.          if (dataFiles(0) ne '') then begin
  5192.             ans = WIDGET_MESSAGE('File exists.   Overwrite ?', /QUESTION)
  5193.             WIDGET_CONTROL, /HOURGLASS
  5194.             if (ans ne 'Yes') then begin
  5195.                WIDGET_CONTROL, mainID, SET_UVALUE=sMainState, /NO_COPY
  5196.                return
  5197.             endif
  5198.          endif
  5199.  
  5200.          x1 = sMainState.sBlockState.c1(0) < sMainState.sBlockState.c2(0)
  5201.          y1 = sMainState.sBlockState.c1(1) < sMainState.sBlockState.c2(1)
  5202.          z1 = sMainState.sBlockState.c1(2) < sMainState.sBlockState.c2(2)
  5203.          x2 = sMainState.sBlockState.c1(0) > sMainState.sBlockState.c2(0)
  5204.          y2 = sMainState.sBlockState.c1(1) > sMainState.sBlockState.c2(1)
  5205.          z2 = sMainState.sBlockState.c1(2) > sMainState.sBlockState.c2(2)
  5206.  
  5207.          GET_LUN, lun
  5208.          OPENW, lun, dataFile
  5209.  
  5210.          HANDLE_VALUE, sMainState.hDataList, lData3D, /NO_COPY
  5211.          HANDLE_VALUE, sMainState.hDataName, dataNames, /NO_COPY
  5212.  
  5213.          for i=0, N_ELEMENTS(lData3D)-1L do begin
  5214.             HANDLE_VALUE, lData3D(i), data3D, /NO_COPY
  5215.             WRITEU, lun, SIZE(data3D(x1:x2, y1:y2, z1:z2))
  5216.             WRITEU, lun, STRLEN(dataNames(i))
  5217.             WRITEU, lun, BYTE(dataNames(i))
  5218.             WRITEU, lun, data3D(x1:x2, y1:y2, z1:z2)
  5219.             HANDLE_VALUE, lData3D(i), data3D, /NO_COPY, /SET
  5220.          endfor
  5221.  
  5222.          HANDLE_VALUE, sMainState.hDataName, dataNames, /NO_COPY, /SET
  5223.          HANDLE_VALUE, sMainState.hDataList, lData3D, /NO_COPY, /SET
  5224.  
  5225.          CLOSE, lun
  5226.          FREE_LUN, lun
  5227.       end
  5228.  
  5229.       'wOptionsBttn': begin ; Options.
  5230.          wOptBase = WIDGET_BASE(TITLE='Slicer3', GROUP_LEADER=event.top, $
  5231.                        /COLUMN, XPAD=1, YPAD=1, SPACE=1, /MODAL)
  5232.  
  5233.          wOptAxisBase = WIDGET_BASE(wOptBase, /ROW, /FRAME, $
  5234.                                     XPAD=1, YPAD=1, SPACE=1)
  5235.          wOptAxisLab = WIDGET_LABEL(wOptAxisBase, VALUE='Axis')
  5236.          wOptAxisExBase = WIDGET_BASE(wOptAxisBase, /ROW, /EXCLUSIVE, $
  5237.                                       XPAD=1, YPAD=1, SPACE=1)
  5238.          wOptAxisOnBttn = WIDGET_BUTTON(wOptAxisExBase, VALUE='On', $
  5239.                              UVALUE='wOptAxisOnBttn', /NO_RELEASE)
  5240.          wOptAxisOffBttn = WIDGET_BUTTON(wOptAxisExBase, VALUE='Off', $
  5241.                               UVALUE='wOptAxisOffBttn', /NO_RELEASE)
  5242.          if (sMainState.axisOn) then $
  5243.             WIDGET_CONTROL, wOptAxisOnBttn, /SET_BUTTON $
  5244.          else WIDGET_CONTROL, wOptAxisOffBttn, /SET_BUTTON
  5245.  
  5246.          wOptCubeBase = WIDGET_BASE(wOptBase, /ROW, /FRAME, $
  5247.                                     XPAD=1, YPAD=1, SPACE=1)
  5248.          wOptCubeLab = WIDGET_LABEL(wOptCubeBase, VALUE='Cube')
  5249.          wOptCubeExBase = WIDGET_BASE(wOptCubeBase, /ROW, /EXCLUSIVE, $
  5250.                                       XPAD=1, YPAD=1, SPACE=1)
  5251.          wOptCubeOnBttn = WIDGET_BUTTON(wOptCubeExBase, VALUE='On', $
  5252.                              UVALUE='wOptCubeOnBttn', /NO_RELEASE)
  5253.          wOptCubeOffBttn = WIDGET_BUTTON(wOptCubeExBase, VALUE='Off', $
  5254.                               UVALUE='wOptCubeOffBttn', /NO_RELEASE)
  5255.          if (sMainState.cubeOn) then $
  5256.             WIDGET_CONTROL, wOptcubeOnBttn, /SET_BUTTON $
  5257.          else WIDGET_CONTROL, wOptcubeOffBttn, /SET_BUTTON
  5258.  
  5259.          wOptSizeBase = WIDGET_BASE(wOptBase, /ROW, XPAD=1, YPAD=1, $
  5260.                                     SPACE=1)
  5261.          wOptSizeLab = WIDGET_LABEL(wOptSizeBase, VALUE='Window Size')
  5262.          wOptSizeText = WIDGET_TEXT(wOptSizeBase, UVALUE='wOptSizeText', $
  5263.                            VALUE=STRING(sMAinState.winX), /EDITABLE)
  5264.  
  5265.          wOptBttnBase = WIDGET_BASE(wOptBase, /ROW, XPAD=1, YPAD=1, $
  5266.                                     SPACE=1)
  5267.          wOptOkBttn = WIDGET_BUTTON(wOptBttnBase, VALUE='Ok', $
  5268.                          UVALUE='wOptOkBttn', /ALIGN_LEFT)
  5269.          wOptCanBttn = WIDGET_BUTTON(wOptBttnBase, VALUE='Cancel', $
  5270.                           UVALUE='wOptCanBttn', /ALIGN_RIGHT)
  5271.  
  5272.          sOptState = {SOptState, Ok:0, axisOn:sMainState.axisOn, $
  5273.                       cubeOn:sMainState.cubeOn, winXY:sMainState.winX, $
  5274.                       wOptSizeText:wOptSizeText}
  5275.          hState = HANDLE_CREATE(VALUE=sOptState, /NO_COPY)
  5276.          WIDGET_CONTROL, wOptBase, SET_UVALUE=hState
  5277.  
  5278.          WIDGET_CONTROL, wOptBase, /REALIZE
  5279.          XMANAGER, 'Viz3D_Event', wOptBase, $
  5280.             EVENT_HANDLER='Viz3D_OptEvent', /MODAL
  5281.          WIDGET_CONTROL, /HOURGLASS
  5282.  
  5283.          HANDLE_VALUE, hState, sOptState, /NO_COPY
  5284.          HANDLE_FREE, hState
  5285.          if (sOptState.Ok) then begin ; User clicked Ok.
  5286.  
  5287.             if ((sOptState.winXY ne sMainState.winX) or $
  5288.                 (sOptState.winXY ne sMainState.winY)) then begin
  5289.                ; Resize window.
  5290.                sMainState.winX = sOptState.winXY
  5291.                sMainState.winY = sOptState.winXY
  5292.                sMainState.cubeOn = sOptState.cubeOn
  5293.                sMainState.axisOn = sOptState.axisOn
  5294.  
  5295.                SET_PLOT, 'Z'
  5296.                DEVICE, SET_RESOLUTION=[sMainState.winX, sMainState.winY], $
  5297.                        /Z_BUFFERING
  5298.                SET_PLOT, sMainState.screenDevice
  5299.                WDELETE, sMainState.pixWin
  5300.                WINDOW, /FREE, /PIXMAP, XSIZE=sMainState.winX, $
  5301.                   YSIZE=sMainState.winY, RETAIN=2
  5302.                sMainState.pixWin = !D.Window
  5303.  
  5304.                WIDGET_CONTROL, sMainState.wMainDraw, /DESTROY
  5305.                sMainState.wMainDraw = WIDGET_DRAW(sMainState.wDrawBase, $
  5306.                   XSIZE=sMainState.winX, YSIZE=sMainState.winY, RETAIN=2, $
  5307.                   UVALUE='wMainDraw', /BUTTON_EVENTS)
  5308.                WIDGET_CONTROL, sMainState.wMainDraw, GET_VALUE=mainWin
  5309.                sMainState.mainWin = mainWin
  5310.                WSET, sMainState.mainWin
  5311.  
  5312.                Viz3D_FillDepth, sMainState
  5313.                Viz3D_Redraw, sMainState
  5314.             endif else begin
  5315.                if (((sMainState.cubeOn eq 1) and (sOptState.cubeOn eq 0)) or $
  5316.                    ((sMainState.axisOn eq 1) and (sOptState.axisOn eq 0))) $
  5317.                then begin
  5318.                   sMainState.cubeOn = sOptState.cubeOn
  5319.                   sMainState.axisOn = sOptState.axisOn
  5320.                   Viz3D_Redraw, sMainState
  5321.                endif else begin
  5322.                   sMainState.cubeOn = sOptState.cubeOn
  5323.                   sMainState.axisOn = sOptState.axisOn
  5324.                   Viz3D_DrawData, sMainState
  5325.                endelse
  5326.             endelse
  5327.          endif
  5328.       end
  5329.  
  5330.       'wEraseBttn': begin ; Erase.
  5331.          ; Clean out the display list.
  5332.          HANDLE_FREE, sMainState.hDisplayList
  5333.          sMainState.hDisplayList = HANDLE_CREATE(sMainState.hMain)
  5334.          if (sMainState.actMode eq 7) then begin
  5335.             ; View mode, redraw small slice and block windows.
  5336.             Viz3D_SliceShow, sMainState
  5337.             Viz3D_BlockShow, sMainState
  5338.          endif
  5339.          ; Repair "Delete" menu.
  5340.          delBttn = WIDGET_INFO(sMainState.wDeleteMenu, /CHILD)
  5341.          WHILE (WIDGET_INFO(delBttn, /VALID_ID)) DO BEGIN
  5342.             WIDGET_CONTROL, delBttn, /DESTROY
  5343.             delBttn = WIDGET_INFO(sMainState.wDeleteMenu, /CHILD)
  5344.          ENDWHILE
  5345.          ; Erase.
  5346.          SET_PLOT, 'Z'
  5347.          ERASE
  5348.          Viz3D_DrawData, sMainState
  5349.       end
  5350.  
  5351.       'wDeleteBttn': begin ; Delete a graphic.
  5352.          ; Determine which button in the menu was chosen
  5353.          widBttn = WIDGET_INFO(sMainState.wDeleteMenu, /Child)
  5354.          hGraphic = HANDLE_INFO(sMainState.hDisplayList, /FIRST_CHILD)
  5355.          WHILE (widBttn ne event.id) do begin
  5356.             widBttn = WIDGET_INFO(widBttn, /SIBLING)
  5357.             hGraphic = HANDLE_INFO(hGraphic, /SIBLING)
  5358.          ENDWHILE
  5359.          ; Delete and redraw.
  5360.          HANDLE_FREE, hGraphic
  5361.          WIDGET_CONTROL, widBttn, /DESTROY
  5362.          Viz3D_Redraw, sMainState
  5363.       end
  5364.  
  5365.       'wColResetBttn': begin ; Reset Colors.
  5366.          sMainState.sColorState = Viz3D_LoadColor(DIFFSHADE=20)
  5367.          WSET, sMainState.mainWin
  5368.          Viz3D_DrawData, sMainState
  5369.       end
  5370.  
  5371.       'wColDiffBttn': begin ; Differential shading.
  5372.          diffBase = WIDGET_BASE(TITLE='Slicer3', XPAD=1, YPAD=1, SPACE=1, $
  5373.             /COLUMN, UVALUE=event.top, GROUP_LEADER=event.top, /MODAL)
  5374.          wDiffSlid = WIDGET_SLIDER(diffBase, MIN=0, MAX=100, /DRAG, $
  5375.                         TITLE='Differential Shading (%)', $
  5376.                         VALUE=sMainState.sColorState.diffShade, $
  5377.                         UVALUE='wDiffSlid')
  5378.          wDiffCloseBttn = WIDGET_BUTTON(diffBase, VALUE='Close', $
  5379.                              UVALUE='wDiffCloseBttn')
  5380.          WIDGET_CONTROL, diffBase, /REALIZE
  5381.          WIDGET_CONTROL, event.top, SET_UVALUE=sMainState, /NO_COPY
  5382.          XMANAGER, 'Viz3D_Event', diffBase, $
  5383.             EVENT_HANDLER='Viz3D_DiffShadeEvent', /MODAL
  5384.          WIDGET_CONTROL, event.top, GET_UVALUE=sMainState, /NO_COPY
  5385.          Viz3D_DrawData, sMainState
  5386.       end
  5387.       'wColSliceBttn': begin ; Slice/block colors.
  5388.          saveP = !P
  5389.          saveX = !X
  5390.          saveY = !Y
  5391.          saveZ = !Z
  5392.          XLOADCT, BOTTOM=0, /USE_CURRENT, $
  5393.             NCOLORS=sMainState.sColorState.nColor, GROUP=event.top, /MODAL
  5394.          WIDGET_CONTROL, /HOURGLASS
  5395.          WSET, sMainState.mainWin
  5396.          !P = TEMPORARY(saveP)
  5397.          !X = TEMPORARY(saveX)
  5398.          !Y = TEMPORARY(saveY)
  5399.          !Z = TEMPORARY(saveZ)
  5400.          sViz3DColors = sMainState.sColorState
  5401.          TVLCT, r, g, b, /GET
  5402.          sViz3DColors.rSlice = r(0:sMainState.sColorState.nColor-1)
  5403.          sViz3DColors.gSlice = g(0:sMainState.sColorState.nColor-1)
  5404.          sViz3DColors.bSlice = b(0:sMainState.sColorState.nColor-1)
  5405.          Viz3D_DiffColor, sViz3DColors
  5406.          sMainState.sColorState = TEMPORARY(sViz3DColors)
  5407.          if (sMainState.sColorState.displayBits eq 24) then LOADCT, 0
  5408.          Viz3D_DrawData, sMainState
  5409.       end
  5410.       'wColSurfBttn': begin ; Surface colors.
  5411.          saveP = !P
  5412.          saveX = !X
  5413.          saveY = !Y
  5414.          saveZ = !Z
  5415.          XLOADCT, BOTTOM=(3*sMainState.sColorState.nColor), /USE_CURRENT, $
  5416.             NCOLORS=sMainState.sColorState.nColor, GROUP=event.top, /MODAL
  5417.          WIDGET_CONTROL, /HOURGLASS
  5418.          WSET, sMainState.mainWin
  5419.          !P = TEMPORARY(saveP)
  5420.          !X = TEMPORARY(saveX)
  5421.          !Y = TEMPORARY(saveY)
  5422.          !Z = TEMPORARY(saveZ)
  5423.          if (sMainState.sColorState.displayBits eq 24) then LOADCT, 0
  5424.          Viz3D_DrawData, sMainState
  5425.       end
  5426.       'wColProjBttn': begin ; Projection colors.
  5427.          saveP = !P
  5428.          saveX = !X
  5429.          saveY = !Y
  5430.          saveZ = !Z
  5431.          XLOADCT, BOTTOM=(4*sMainState.sColorState.nColor), /USE_CURRENT, $
  5432.             NCOLORS=sMainState.sColorState.nColor, GROUP=event.top, /MODAL
  5433.          WIDGET_CONTROL, /HOURGLASS
  5434.          WSET, sMainState.mainWin
  5435.          !P = TEMPORARY(saveP)
  5436.          !X = TEMPORARY(saveX)
  5437.          !Y = TEMPORARY(saveY)
  5438.          !Z = TEMPORARY(saveZ)
  5439.          if (sMainState.sColorState.displayBits eq 24) then LOADCT, 0
  5440.          Viz3D_DrawData, sMainState
  5441.       end
  5442.  
  5443.       'wAnimateBttn': begin ; Animate
  5444.          ; *** Future animation functionality.
  5445.       end
  5446.  
  5447.       'wHelpBttn': begin ; Help
  5448.          XDISPLAYFILE, FILEPATH("slicer3.txt", $
  5449.                 SUBDIR=['help', 'widget']), $
  5450.                 TITLE="Slicer3 Help", $
  5451.                 GROUP=event.top, $
  5452.                 WIDTH=72, HEIGHT=24
  5453.       end
  5454.  
  5455.       'wDataDrop': begin ; Set data.
  5456.          if (event.index ne sMainState.curData) then begin
  5457.             sMainState.curData = event.index
  5458.             sMainState.sSurfState.curShade = event.index
  5459.             HANDLE_VALUE, sMainState.hDataName, dName
  5460.             sName = dName
  5461.             sName(event.index) = 'Light-source'
  5462.             WIDGET_CONTROL, sMainState.sSurfState.wSurfShadeDrop, $
  5463.                SET_VALUE=sName, /NO_COPY
  5464.             WIDGET_CONTROL, sMainState.sSurfState.wSurfShadeDrop, $
  5465.                SET_DROPLIST_SELECT=event.index
  5466.             Viz3D_SurfShow, sMainState, /CALC_HIST
  5467.             Viz3D_ThreshShow, sMainState
  5468.          endif
  5469.       end
  5470.  
  5471.       'wModeDrop': begin ; Set mode.
  5472.          case event.index of
  5473.             0: begin ; Slice mode.
  5474.                if (sMainState.actMode ne 0) then begin
  5475.                   WIDGET_CONTROL, sMainState.wStatText, SET_VALUE=''
  5476.                   WIDGET_CONTROL, sMainState.wCurMapBase, MAP=0
  5477.                   WIDGET_CONTROL, sMainState.wSliceBase, /MAP
  5478.                   sMainState.wCurMapBase = sMainState.wSliceBase
  5479.                   sMainState.actMode = 0
  5480.                   WIDGET_CONTROL, sMainState.wDrawBase, $
  5481.                      EVENT_PRO='Viz3D_SliceEvent'
  5482.                   WIDGET_CONTROL, sMainState.wSaveSubsetBttn, SENSITIVE=0
  5483.                endif
  5484.             end
  5485.             1: begin ; Block mode.
  5486.                if (sMainState.actMode ne 1) then begin
  5487.                   WIDGET_CONTROL, sMainState.wStatText, SET_VALUE=''
  5488.                   WIDGET_CONTROL, sMainState.wCurMapBase, MAP=0
  5489.                   WIDGET_CONTROL, sMainState.wBlockBase, /MAP
  5490.                   sMainState.wCurMapBase = sMainState.wBlockBase
  5491.                   sMainState.actMode = 1
  5492.                   WIDGET_CONTROL, sMainState.wDrawBase, $
  5493.                      EVENT_PRO='Viz3D_BlockEvent'
  5494.                   Viz3D_BlockShow, sMainState
  5495.                   Viz3D_BlockShow, sMainState, /DIRECT
  5496.  
  5497.                   WIDGET_CONTROL, sMainState.wStatText, SET_VALUE=('(' + $
  5498.                      STRTRIM(STRING(sMainState.sBlockState.c1(0)),2) + $
  5499.                      ', ' + $
  5500.                      STRTRIM(STRING(sMainState.sBlockState.c1(1)),2) + $
  5501.                      ', ' + $
  5502.                      STRTRIM(STRING(sMainState.sBlockState.c1(2)),2) + $
  5503.                      '), (' + $
  5504.                      STRTRIM(STRING(sMainState.sBlockState.c2(0)),2) + $
  5505.                      ', ' + $
  5506.                      STRTRIM(STRING(sMainState.sBlockState.c2(1)),2) + $
  5507.                      ', ' + $
  5508.                      STRTRIM(STRING(sMainState.sBlockState.c2(2)),2) + ')')
  5509.  
  5510.                   sMainState.cleanupView = 1
  5511.                   WIDGET_CONTROL, sMainState.wSaveSubsetBttn, SENSITIVE=1
  5512.                endif
  5513.             end
  5514.             2: begin ; Surface mode.
  5515.                if (sMainState.actMode ne 2) then begin
  5516.                   WIDGET_CONTROL, sMainState.wStatText, SET_VALUE=''
  5517.                   WIDGET_CONTROL, sMainState.wCurMapBase, MAP=0
  5518.                   WIDGET_CONTROL, sMainState.wSurfBase, /MAP
  5519.                   sMainState.wCurMapBase = sMainState.wSurfBase
  5520.                   sMainState.actMode = 2
  5521.                   WIDGET_CONTROL, sMainState.wDrawBase, $
  5522.                      EVENT_PRO='Viz3D_SurfEvent'
  5523.                   WIDGET_CONTROL, sMainState.wSaveSubsetBttn, SENSITIVE=0
  5524.                endif
  5525.             end
  5526.             3: begin ; Projection mode.
  5527.                if (sMainState.actMode ne 4) then begin
  5528.                   WIDGET_CONTROL, sMainState.wStatText, SET_VALUE=''
  5529.                   WIDGET_CONTROL, sMainState.wCurMapBase, MAP=0
  5530.                   WIDGET_CONTROL, sMainState.wProjectBase, /MAP
  5531.                   sMainState.wCurMapBase = sMainState.wProjectBase
  5532.                   sMainState.actMode = 4
  5533.                   WIDGET_CONTROL, sMainState.wDrawBase, $
  5534.                      EVENT_PRO='Viz3D_ProjectEvent'
  5535.                   WIDGET_CONTROL, sMainState.wSaveSubsetBttn, SENSITIVE=0
  5536.                endif
  5537.             end
  5538.             4: begin ; Threshold mode.
  5539.                if (sMainState.actMode ne 3) then begin
  5540.                   WIDGET_CONTROL, sMainState.wStatText, SET_VALUE=''
  5541.                   WIDGET_CONTROL, sMainState.wCurMapBase, MAP=0
  5542.                   WIDGET_CONTROL, sMainState.wThreshBase, /MAP
  5543.                   sMainState.wCurMapBase = sMainState.wThreshBase
  5544.                   sMainState.actMode = 3
  5545.                   WIDGET_CONTROL, sMainState.wDrawBase, $
  5546.                      EVENT_PRO='Viz3D_ThreshEvent'
  5547.                   WIDGET_CONTROL, sMainState.wSaveSubsetBttn, SENSITIVE=0
  5548.                endif
  5549.             end
  5550.             5: begin ; Profile mode.
  5551.                if (sMainState.actMode ne 5) then begin
  5552.                   WIDGET_CONTROL, sMainState.wStatText, SET_VALUE=''
  5553.                   WIDGET_CONTROL, sMainState.wCurMapBase, MAP=0
  5554.                   WIDGET_CONTROL, sMainState.wProfileBase, /MAP
  5555.                   sMainState.wCurMapBase = sMainState.wProfileBase
  5556.                   sMainState.actMode = 5
  5557.                   WIDGET_CONTROL, sMainState.wDrawBase, $
  5558.                      EVENT_PRO='Viz3D_ProfileEvent'
  5559.                   Viz3D_ProfShow, sMainState
  5560.                   Viz3D_ProfDraw, sMainState
  5561.                   sMainState.cleanupView = 1
  5562.                   WIDGET_CONTROL, sMainState.wSaveSubsetBttn, SENSITIVE=0
  5563.                endif
  5564.             end
  5565.             6: begin ; Probe mode.
  5566.                if (sMainState.actMode ne 6) then begin
  5567.                   WIDGET_CONTROL, sMainState.wStatText, SET_VALUE=''
  5568.                   WIDGET_CONTROL, sMainState.wCurMapBase, MAP=0
  5569.                   WIDGET_CONTROL, sMainState.wProbeBase, /MAP
  5570.                   sMainState.wCurMapBase = sMainState.wProbeBase
  5571.                   sMainState.actMode = 6
  5572.                   WIDGET_CONTROL, sMainState.wDrawBase, $
  5573.                      EVENT_PRO='Viz3D_ProbeEvent'
  5574.                   sMainState.cleanupView = 1
  5575.                   WIDGET_CONTROL, sMainState.wSaveSubsetBttn, SENSITIVE=0
  5576.                   Viz3D_ProbeDraw, sMainState
  5577.                endif
  5578.             end
  5579.             7: begin ; View mode.
  5580.                if (sMainState.actMode ne 7) then begin
  5581.                   WIDGET_CONTROL, sMainState.wStatText, SET_VALUE=''
  5582.                   WIDGET_CONTROL, sMainState.wCurMapBase, MAP=0
  5583.                   WIDGET_CONTROL, sMainState.wViewBase, /MAP
  5584.                   sMainState.wCurMapBase = sMainState.wViewBase
  5585.                   sMainState.actMode = 7
  5586.                   WIDGET_CONTROL, sMainState.wDrawBase, $
  5587.                      EVENT_PRO='Viz3D_ViewEvent'
  5588.                   WIDGET_CONTROL, sMainState.wSaveSubsetBttn, SENSITIVE=0
  5589.                endif
  5590.             end
  5591.          endcase
  5592.       end
  5593.       else:
  5594.    endcase
  5595.  
  5596.    WIDGET_CONTROL, mainID, SET_UVALUE=sMainState, /NO_COPY
  5597.    return
  5598.  
  5599. IO_BAD:
  5600.  
  5601.    if (NOT(HANDLE_INFO(sMainState.hDataList, /VALID_ID))) then begin
  5602.       ans = WIDGET_MESSAGE(['Unrecoverable I/O error.', $
  5603.                             'Exiting Slicer3.'], /ERROR)
  5604.       HANDLE_FREE, sMainState.hMain
  5605.       WIDGET_CONTROL, event.top, /DESTROY
  5606.       return
  5607.    endif
  5608.  
  5609.    if (N_ELEMENTS(sMainState) gt 0L) then $
  5610.       WIDGET_CONTROL, mainID, SET_UVALUE=sMainState, /NO_COPY
  5611.  
  5612.    if (n_elements(fLun) gt 0L) then begin
  5613.       CLOSE, fLun
  5614.       FREE_LUN, fLun
  5615.    endif
  5616.  
  5617.    ans = WIDGET_MESSAGE('Unknown I/O error.', /ERROR)
  5618.  
  5619. end
  5620. ;******************************************************************************
  5621.  
  5622.  
  5623. ;******************************************************************************
  5624. ; Procedure to clean up the main draw window if it needs it.
  5625.  
  5626. pro Viz3D_CleanView, sMainState, SKIP_BUFFER=skipBuffer
  5627.  
  5628.    if (not(KEYWORD_SET(skipBuffer))) then $
  5629.       Viz3D_CleanBuffer, sMainState
  5630.  
  5631.    if (sMainState.cleanupView) then begin
  5632.       WSET, sMainState.mainWin
  5633.       DEVICE, COPY=[0, 0, sMainState.winX, sMainState.winY, $
  5634.                     0, 0, sMainState.pixWin]
  5635.       sMainState.cleanupView = 0
  5636.    endif
  5637. end
  5638. ;******************************************************************************
  5639.  
  5640.  
  5641. ;******************************************************************************
  5642. ; Procedure to clean up (redraw) the Z buffer (and other windows) if needed.
  5643.  
  5644. pro Viz3D_CleanBuffer, sMainState
  5645.    if (sMainState.cleanupBuffer) then begin
  5646.       Viz3D_FillDepth, sMainState
  5647.       Viz3D_SliceShow, sMainState
  5648.       Viz3D_BlockShow, sMainState
  5649.       Viz3D_SurfShow, sMainState
  5650.       Viz3D_ThreshShow, sMainState, /DYNAMIC
  5651.       Viz3D_ViewShow, sMainState
  5652.       Viz3D_ProfShow, sMainState
  5653.       Viz3D_Redraw, sMainState
  5654.    endif
  5655. end
  5656. ;******************************************************************************
  5657.  
  5658.  
  5659. ;******************************************************************************
  5660. ; Cleanup handler for detached base.
  5661.  
  5662. pro Viz3D_KillDraw, wDrawBase
  5663.  
  5664.    WIDGET_CONTROL, wDrawBase, GET_UVALUE=wMainBase, /NO_COPY
  5665.  
  5666.    if (HANDLE_INFO(wMainBase, /VALID_ID)) then begin
  5667.       WIDGET_CONTROL, wMainBase, GET_UVALUE=sMainState, /NO_COPY
  5668.       WIDGET_CONTROL, wMainBase, KILL_NOTIFY=''
  5669.       WIDGET_CONTROL, wMainBase, /DESTROY
  5670.       HANDLE_FREE, sMainState.hMain
  5671.       WDELETE, sMainState.pixWin
  5672.       WDELETE, sMainState.sProfState.profPix
  5673.       WDELETE, sMainState.sSurfState.surfPix
  5674.       WDELETE, sMainState.sThreshState.threshPix
  5675.    endif
  5676.  
  5677. end
  5678. ;******************************************************************************
  5679.  
  5680.  
  5681. ;******************************************************************************
  5682. ; Cleanup handler for main window.
  5683.  
  5684. pro Viz3D_KillMain, wMainBase
  5685.  
  5686.    WIDGET_CONTROL, wMainBase, GET_UVALUE=sMainState, /NO_COPY
  5687.    if (sMainState.detachBase) then begin
  5688.       WIDGET_CONTROL, sMainState.wDrawBase, KILL_NOTIFY=''
  5689.       WIDGET_CONTROL, sMainState.wDrawBase, /DESTROY
  5690.    end
  5691.  
  5692.    HANDLE_FREE, sMainState.hMain
  5693.    WDELETE, sMainState.pixWin
  5694.    WDELETE, sMainState.sProfState.profPix
  5695.    WDELETE, sMainState.sSurfState.surfPix
  5696.    WDELETE, sMainState.sThreshState.threshPix
  5697.  
  5698. end
  5699. ;******************************************************************************
  5700.  
  5701.  
  5702. ;******************************************************************************
  5703. ; Main procedure (entry point).
  5704.  
  5705. pro Slicer3, hData3D, DATA_NAMES=dataNames, DETACH=detachView, $
  5706.              GROUP=groupLead, MODAL=runModal
  5707.  
  5708.    ; Use the "Colors" common block to save the current colortable.
  5709.    common colors, r, g, b, cur_red, cur_green, cur_blue
  5710.    IF (N_ELEMENTS(r) LE 0L) THEN LOADCT, 0
  5711.    saveR = r
  5712.    saveG = g
  5713.    saveB = b
  5714.    save_curR = cur_red
  5715.    save_curG = cur_green
  5716.    save_curB = cur_blue
  5717.  
  5718.    ; Check the incoming data (if any).
  5719.  
  5720.    maxHand = N_ELEMENTS(hData3D) - 1L
  5721.    if (maxHand ge 0L) then begin
  5722.       minData = DBLARR(N_ELEMENTS(hData3D))
  5723.       maxData = minData
  5724.  
  5725.       for i=0, maxHand do begin
  5726.  
  5727.          if NOT(HANDLE_INFO(hData3D(i), /VALID_ID)) then begin
  5728.             PRINT, "Slicer3: data handle is not valid."
  5729.             return
  5730.          endif
  5731.          HANDLE_VALUE, hData3D(i), data3D, /NO_COPY
  5732.  
  5733.          neData = N_ELEMENTS(data3D)
  5734.          if (neData le 0L) then begin
  5735.             PRINT, "Slicer3: data handle does not contain valid data."
  5736.             return
  5737.          endif
  5738.          szData = SIZE(data3D)
  5739.          maxData(i) = MAX(data3D, MIN=minVal)
  5740.          minData(i) = minVal
  5741.          if (minData(i) eq maxData(i)) then maxData(i) = maxData(i) + 1.0D
  5742.          HANDLE_VALUE, hData3D(i), data3D, /NO_COPY, /SET
  5743.  
  5744.          if (szData(0) ne 3L) then begin
  5745.             PRINT, "Slicer3: data does not have 3 dimensions."
  5746.             return
  5747.          endif else begin
  5748.             if (min(szData(1:3)) le 1L) then begin
  5749.                PRINT, $
  5750.                   "Slicer3: all 3 dimensions of data must be greater than 1."
  5751.                return
  5752.             endif
  5753.          endelse
  5754.  
  5755.          if (i eq 0) then sz1 = szData else begin
  5756.             diffDim = WHERE(szData(0:3) ne sz1(0:3))
  5757.             if (diffDim(0) ne (-1)) then begin
  5758.                PRINT, $
  5759.                   "Slicer3: all data sets must have the same dimensions."
  5760.                return
  5761.             endif
  5762.          endelse
  5763.  
  5764.       endfor
  5765.       defaultData = 0
  5766.    endif else begin
  5767.       data3D = BYTARR(2, 2, 2)
  5768.       szData = SIZE(data3D)
  5769.       minData = 0.0D
  5770.       maxData = 1.0D
  5771.       defaultData = 1
  5772.       dataNames = 'No Data'
  5773.       maxHand = 0
  5774.    endelse
  5775.  
  5776.    ; Main handles.
  5777.    hMain = HANDLE_CREATE()
  5778.    if (defaultData) then $
  5779.       hData3D = HANDLE_CREATE(hMain, VALUE=data3D, /NO_COPY)
  5780.    hDataList = HANDLE_CREATE(hMain, VALUE=hData3D)
  5781.    hDisplayList = HANDLE_CREATE(hMain)
  5782.  
  5783.    ; Compute and store the histograms for each set of data.
  5784.    lDataHist = LONARR(N_ELEMENTS(hData3D))
  5785.    lRangeHist = LONARR(N_ELEMENTS(hData3D))
  5786.    for i=0, maxHand do begin
  5787.       HANDLE_VALUE, hData3D(i), data3D, /NO_COPY
  5788.       bSize = (maxData(i) - minData(i)) / 200.0
  5789.       dataHist = HISTOGRAM(FLOAT(data3D), MIN=minData(i), MAX=maxData(i), $
  5790.                     BINSIZE=bSize) > 1.0
  5791.       HANDLE_VALUE, hData3D(i), data3D, /NO_COPY, /SET
  5792.  
  5793.       ; Histogram will be displayed as a LOG plot.
  5794.       dataHist = ALOG(FLOAT(TEMPORARY(dataHist))) > 0.0
  5795.  
  5796.       lDataHist(i) = HANDLE_CREATE(hMain, VALUE=dataHist)
  5797.       lRangeHist(i) = HANDLE_CREATE(hMain, VALUE=dataHist, /NO_COPY)
  5798.    endfor
  5799.    hDataHist = HANDLE_CREATE(hMain, VALUE=lDataHist, /NO_COPY)
  5800.    hRangeHist = HANDLE_CREATE(hMain, VALUE=lRangeHist, /NO_COPY)
  5801.  
  5802.    ; Store the name for each set of data.
  5803.    dName = STRARR(N_ELEMENTS(hData3D))
  5804.    for i=0, maxHand do $
  5805.       if (i lt N_ELEMENTS(dataNames)) then $
  5806.          dName(i) = STRTRIM(STRING(dataNames(i)), 2) $
  5807.       else $
  5808.          dName(i) = 'Data ' + STRTRIM(STRING(i), 2)
  5809.    hDataName = HANDLE_CREATE(hMain, VALUE=dName)
  5810.  
  5811.  
  5812.    ; Save the current system variables.
  5813.    saveOrder = !Order
  5814.    saveP = !P
  5815.    saveX = !X
  5816.    saveY = !Y
  5817.    saveZ = !Z
  5818.    saveWin = !D.Window
  5819.  
  5820.    ; Reset system variables to startup state.
  5821.    Viz3D_Reset
  5822.  
  5823.    ; Initialize parameters.
  5824.  
  5825.    DEVICE, GET_SCREEN_SIZE=screenSize
  5826.    winX = ((screenSize(0) / 2) < 640) > 320 ; View window size.
  5827.    winY = ((screenSize(1) / 2) < 640) > 320 ; View window size.
  5828.    winX = 8 * ((winX < winY) / 8)
  5829.    winY = winX
  5830.  
  5831.    detachBase = KEYWORD_SET(detachView)
  5832.  
  5833.    ; Create the widgets.
  5834.  
  5835.    if (N_ELEMENTS(groupLead) LE 0L) then groupLead = 0L
  5836.    if (WIDGET_INFO(groupLead, /VALID_ID)) then begin
  5837.       wMainBase = WIDGET_BASE(TITLE='IDL 3D Data Visualizer (Slicer3)', $
  5838.          APP_MBAR=wBarBase, /ROW, SPACE=1, XPAD=1, YPAD=1, $
  5839.          GROUP_LEADER=groupLead)
  5840.    endif else begin
  5841.       wMainBase = WIDGET_BASE(TITLE='IDL 3D Data Visualizer (Slicer3)', $
  5842.          APP_MBAR=wBarBase, /ROW, SPACE=1, XPAD=1, YPAD=1)
  5843.    endelse
  5844.  
  5845.    WIDGET_CONTROL, wMainBase, /MANAGED
  5846.    wFileMenu = WIDGET_BUTTON(wBarBase, VALUE='File', /MENU)
  5847.    wToolMenu = WIDGET_BUTTON(wBarBase, VALUE='Tools', /MENU)
  5848.    wHelpMenu = WIDGET_BUTTON(wBarBase, VALUE='About', /MENU, /HELP)
  5849.    wHelpBttn = WIDGET_BUTTON(wHelpMenu, VALUE='About Slicer', $
  5850.                              UVALUE='wHelpBttn')
  5851.  
  5852.    wLoadBttn = WIDGET_BUTTON(wFileMenu, VALUE='Load', UVALUE='wLoadBttn')
  5853.  
  5854.    wSaveMenu = WIDGET_BUTTON(wFileMenu, VALUE='Save', /MENU, /SEPARATOR)
  5855.    wSaveSubsetBttn = WIDGET_BUTTON(wSaveMenu, VALUE='Save Subset', $
  5856.                         UVALUE='wSaveSubsetBttn')
  5857.    WIDGET_CONTROL, wSaveSubsetBttn, SENSITIVE=0
  5858.    wSaveTiffBttn = WIDGET_BUTTON(wSaveMenu, VALUE='Save Tiff Image', $
  5859.                       UVALUE='wSaveTiffBttn')
  5860.  
  5861.  
  5862.    wQuitBttn = WIDGET_BUTTON(wFileMenu, VALUE='Quit', UVALUE='wQuitBttn', $
  5863.                              /SEPARATOR)
  5864.  
  5865.    wEraseBttn = WIDGET_BUTTON(wToolMenu, VALUE='Erase', $
  5866.                                UVALUE='wEraseBttn')
  5867.    wDeleteMenu = WIDGET_BUTTON(wToolMenu, VALUE='Delete', /MENU)
  5868.  
  5869.    wColorsMenu = WIDGET_BUTTON(wToolMenu, VALUE='Colors', /MENU)
  5870.    wColResetBttn = WIDGET_BUTTON(wColorsMenu, VALUE='Reset Colors', $
  5871.                      UVALUE='wColResetBttn')
  5872.    wColDiffBttn = WIDGET_BUTTON(wColorsMenu, VALUE='Differential Shading', $
  5873.                      UVALUE='wColDiffBttn')
  5874.    wColSliceBttn = WIDGET_BUTTON(wColorsMenu, VALUE='Slice/Block', $
  5875.                       UVALUE='wColSliceBttn')
  5876.    wColSurfBttn = WIDGET_BUTTON(wColorsMenu, VALUE='Surface', $
  5877.                      UVALUE='wColSurfBttn')
  5878.    wColProjBttn = WIDGET_BUTTON(wColorsMenu, VALUE='Projection', $
  5879.                      UVALUE='wColProjBttn')
  5880.  
  5881. ;   *** Future animation functionality.
  5882. ;   wAnimateBttn = WIDGET_BUTTON(wToolMenu, VALUE='Animate', $
  5883. ;                     UVALUE='wAnimateBttn')
  5884.  
  5885.    wOptionsBttn = WIDGET_BUTTON(wToolMenu, VALUE='Options', $
  5886.                      UVALUE='wOptionsBttn')
  5887.  
  5888.    wModeBase = WIDGET_BASE(wMainBase, /COLUMN, SPACE=1, XPAD=1, YPAD=1)
  5889.    if ((detachBase) and NOT(KEYWORD_SET(runModal))) then $
  5890.       wDrawBase = WIDGET_BASE(TITLE='IDL 3-D Data Visualizer', $
  5891.          UVALUE=wMainBase, /COLUMN, SPACE=1, XPAD=1, YPAD=1, $
  5892.          EVENT_PRO='Viz3D_SliceEvent') $
  5893.    else $
  5894.       wDrawBase = WIDGET_BASE(wMainBase, UVALUE=wMainBase, /COLUMN, $
  5895.          SPACE=1, XPAD=1, YPAD=1, EVENT_PRO='Viz3D_SliceEvent')
  5896.  
  5897.    wStatText = WIDGET_TEXT(wDrawBase, SCR_XSIZE=winX-12, YSIZE=1, VALUE=' ')
  5898.    wMainDraw = WIDGET_DRAW(wDrawBase, XSIZE=winX, YSIZE=winY, $
  5899.       UVALUE='wMainDraw', RETAIN=2, /BUTTON_EVENTS)
  5900.  
  5901.    wDataModeBase = WIDGET_BASE(wModeBase, /ROW, /FRAME, $
  5902.                                SPACE=1, XPAD=1, YPAD=1)
  5903.    wDataLab = WIDGET_LABEL(wDataModeBase, VALUE='Data:')
  5904.    wDataDrop = WIDGET_DROPLIST(wDataModeBase, VALUE=dName, UVALUE='wDataDrop')
  5905.    if (N_ELEMENTS(dName) le 1L) then $
  5906.       WIDGET_CONTROL, wDataModeBase, SENSITIVE=0
  5907.  
  5908.    modes = ['Slice','Block','Surface','Projection', $
  5909.             'Threshold','Profile','Probe','View']
  5910.    wActModeBase = WIDGET_BASE(wModeBase, /ROW, /FRAME, $
  5911.                               SPACE=1, XPAD=1, YPAD=1)
  5912.    wDataLab = WIDGET_LABEL(wActModeBase, VALUE='Mode:')
  5913.    wModeDrop = WIDGET_DROPLIST(wActModeBase, VALUE=modes, UVALUE='wModeDrop')
  5914.  
  5915.    wMapBase = WIDGET_BASE(wModeBase, /FRAME, SPACE=1, XPAD=1, YPAD=1)
  5916.  
  5917.    wSliceBase = WIDGET_BASE(wMapBase, /COLUMN, SPACE=1, XPAD=1, YPAD=1, $
  5918.       EVENT_PRO='Viz3D_SliceEvent')
  5919.    wBlockBase = WIDGET_BASE(wMapBase, /COLUMN, SPACE=1, XPAD=1, YPAD=1, $
  5920.       MAP=0, EVENT_PRO='Viz3D_BlockEvent')
  5921.    wSurfBase = WIDGET_BASE(wMapBase, /COLUMN, SPACE=1, XPAD=1, YPAD=1, $
  5922.       MAP=0, EVENT_PRO='Viz3D_SurfEvent')
  5923.    wThreshBase = WIDGET_BASE(wMapBase, /COLUMN, SPACE=1, XPAD=1, YPAD=1, $
  5924.       MAP=0, EVENT_PRO='Viz3D_ThreshEvent')
  5925.    wProjectBase = WIDGET_BASE(wMapBase, /COLUMN, SPACE=1, XPAD=1, YPAD=1, $
  5926.       MAP=0, EVENT_PRO='Viz3D_ProjectEvent')
  5927.    wProfileBase = WIDGET_BASE(wMapBase, /COLUMN, SPACE=1, XPAD=1, YPAD=1, $
  5928.       MAP=0, EVENT_PRO='Viz3D_ProfileEvent')
  5929.    wProbeBase = WIDGET_BASE(wMapBase, /COLUMN, SPACE=1, XPAD=1, YPAD=1, $
  5930.       MAP=0, EVENT_PRO='Viz3D_ProbeEvent')
  5931.    wViewBase = WIDGET_BASE(wMapBase, /COLUMN, SPACE=1, XPAD=1, YPAD=1, $
  5932.       MAP=0, EVENT_PRO='Viz3D_ViewEvent')
  5933.  
  5934.  
  5935.    ; Slice base widgets.
  5936.    wSliceDraw = WIDGET_DRAW(wSliceBase, XSIZE=128, YSIZE=128, $
  5937.       RETAIN=2, UVALUE='wSliceDraw', /BUTTON_EVENTS)
  5938.  
  5939.    wBase = WIDGET_BASE(wSliceBase, /ROW, SPACE=1, XPAD=1, YPAD=1, $
  5940.               /EXCLUSIVE, /FRAME)
  5941.    wSliceDrawBttn = WIDGET_BUTTON(wBase, VALUE='Draw', $
  5942.       UVALUE='wSliceDrawBttn', /NO_RELEASE)
  5943.    wSliceExpoBttn = WIDGET_BUTTON(wBase, VALUE='Expose', $
  5944.       UVALUE='wSliceExpoBttn', /NO_RELEASE)
  5945.    WIDGET_CONTROL, wSliceDrawBttn, /SET_BUTTON
  5946.  
  5947.    wBase = WIDGET_BASE(wSliceBase, /COLUMN, SPACE=1, XPAD=1, YPAD=1, $
  5948.               /EXCLUSIVE, /FRAME)
  5949.    wSliceOrthoBttn = WIDGET_BUTTON(wBase, VALUE='Orthogonal', $
  5950.       UVALUE='wSliceOrthoBttn', /NO_RELEASE)
  5951.    wSliceObliqBttn = WIDGET_BUTTON(wBase, VALUE='Oblique', $
  5952.       UVALUE='wSliceObliqBttn', /NO_RELEASE)
  5953.    WIDGET_CONTROL, wSliceOrthoBttn, /SET_BUTTON
  5954.  
  5955.    wSliceMapBase = WIDGET_BASE(wSliceBase, SPACE=1, XPAD=1, YPAD=1, /FRAME)
  5956.    wSliceOrthoBase = WIDGET_BASE(wSliceMapBase, /ROW, SPACE=1, $
  5957.                         XPAD=1, YPAD=1, /EXCLUSIVE)
  5958.    wSliceXBttn = WIDGET_BUTTON(wSliceOrthoBase, VALUE='X', $
  5959.       UVALUE='wSliceXBttn', /NO_RELEASE)
  5960.    wSliceYBttn = WIDGET_BUTTON(wSliceOrthoBase, VALUE='Y', $
  5961.       UVALUE='wSliceYBttn', /NO_RELEASE)
  5962.    wSliceZBttn = WIDGET_BUTTON(wSliceOrthoBase, VALUE='Z', $
  5963.       UVALUE='wSliceZBttn', /NO_RELEASE)
  5964.    WIDGET_CONTROL, wSliceXBttn, /SET_BUTTON
  5965.  
  5966.    wSliceObliqBase = WIDGET_BASE(wSliceMapBase, /Column, SPACE=1, $
  5967.                         XPAD=1, YPAD=1, MAP=0)
  5968.    wSliceObliqBase1 = WIDGET_BASE(wSliceObliqBase, /ROW, SPACE=1, $
  5969.                         XPAD=1, YPAD=1, /EXCLUSIVE)
  5970.    wSliceNormalBttn = WIDGET_BUTTON(wSliceObliqBase1, VALUE='Normal', $
  5971.       UVALUE='wSliceNormalBttn', /NO_RELEASE)
  5972.    wSliceCenterBttn = WIDGET_BUTTON(wSliceObliqBase1, VALUE='Center', $
  5973.       UVALUE='wSliceCenterBttn', /NO_RELEASE)
  5974.    WIDGET_CONTROL, wSliceNormalBttn, /SET_BUTTON
  5975.    wSliceObliqGoBttn = WIDGET_BUTTON(wSliceObliqBase, VALUE='Display', $
  5976.                                      UVALUE='wSliceObliqGoBttn')
  5977.  
  5978.  
  5979.    ; Block base widgets.
  5980.    wBlockDraw = WIDGET_DRAW(wBlockBase, XSIZE=128, YSIZE=128, $
  5981.       RETAIN=2, UVALUE='wBlockDraw', /BUTTON_EVENTS)
  5982.    wBlockModeBase = WIDGET_BASE(wBlockBase, /ROW, /EXCLUSIVE, /FRAME, $
  5983.                        XPAD=1, YPAD=1, SPACE=1)
  5984.    wBlockAddBttn = WIDGET_BUTTON(wBlockModeBase, VALUE='Add', $
  5985.                       UVALUE='wBlockAddBttn', /NO_RELEASE)
  5986.    wBlockSubBttn = WIDGET_BUTTON(wBlockModeBase, VALUE='Subtract', $
  5987.                       UVALUE='wBlockSubBttn', /NO_RELEASE)
  5988.    WIDGET_CONTROL, wBlockAddBttn, /SET_BUTTON
  5989.    wBlockGoBttn = WIDGET_BUTTON(wBlockBase, VALUE='Display', $
  5990.                                 UVALUE='wBlockGoBttn')
  5991.  
  5992.  
  5993.    ; Iso-surface base widgets.
  5994.    wSurfDrawBase = WIDGET_BASE(wSurfBase, /COLUMN, SPACE=1, $
  5995.                                XPAD=1, YPAD=1, /FRAME)
  5996.    wSurfLabel = WIDGET_LABEL(wSurfDrawBase, VALUE='Surface Threshold', $
  5997.                              /ALIGN_LEFT)
  5998.    wSurfDraw = WIDGET_DRAW(wSurfDrawBase, XSIZE=192, YSIZE=128, $
  5999.       RETAIN=2, UVALUE='wSurfDraw', /BUTTON_EVENTS)
  6000.    wSurfText = WIDGET_TEXT(wSurfDrawBase, XSIZE=8, YSIZE=1, /FRAME, $
  6001.                            UVALUE='wSurfText', /EDITABLE)
  6002.    wSurfSideBase = WIDGET_BASE(wSurfBase, /ROW, SPACE=1, /EXCLUSIVE, $
  6003.                                XPAD=1, YPAD=1, /FRAME)
  6004.    wSurfLowBttn = WIDGET_BUTTON(wSurfSideBase, VALUE='Low', $
  6005.                                 UVALUE='wSurfLowBttn', /NO_RELEASE)
  6006.    wSurfHighBttn = WIDGET_BUTTON(wSurfSideBase, VALUE='High', $
  6007.                                  UVALUE='wSurfHighBttn', /NO_RELEASE)
  6008.    WIDGET_CONTROL, wSurfLowBttn, /SET_BUTTON
  6009.    wSurfShadeBase = WIDGET_BASE(wSurfBase, /COLUMN, $
  6010.                        SPACE=1, XPAD=1, YPAD=1, /FRAME)
  6011.    wSurfShadeLab = WIDGET_LABEL(wSurfShadeBase, VALUE='Shading:')
  6012.    sName = dName
  6013.    sName(0) = 'Light-source'
  6014.    wSurfShadeDrop = WIDGET_DROPLIST(wSurfShadeBase, VALUE=sName, $
  6015.       UVALUE='wSurfShadeDrop')
  6016.    if (N_ELEMENTS(sName) LE 1L) then WIDGET_CONTROL, wSurfShadeBase, $
  6017.       SENSITIVE=0
  6018.    wSurfGoBttn = WIDGET_BUTTON(wSurfBase, VALUE='Display', $
  6019.                                      UVALUE='wSurfGoBttn')
  6020.  
  6021.  
  6022.    ; Projection base widgets.
  6023.    wProjTypeBase = WIDGET_BASE(wProjectBase, /COLUMN, SPACE=1, $
  6024.                                XPAD=1, YPAD=1, /FRAME)
  6025.    wProjTypeLab = WIDGET_LABEL(wProjTypeBase, VALUE='Projection Type', $
  6026.                      /ALIGN_LEFT)
  6027.    wProjTypeBase1 = WIDGET_BASE(wProjTypeBase, /ROW, /EXCLUSIVE, SPACE=1, $
  6028.                                XPAD=1, YPAD=1)
  6029.    wProjMaxBttn = WIDGET_BUTTON(wProjTypeBase1, VALUE='Max', $
  6030.                                 UVALUE='wProjMaxBttn', /NO_RELEASE)
  6031.    wProjAvgBttn = WIDGET_BUTTON(wProjTypeBase1, VALUE='Avg', $
  6032.                                 UVALUE='wProjAvgBttn', /NO_RELEASE)
  6033.    WIDGET_CONTROL, wProjMaxBttn, /SET_BUTTON
  6034.    wProjResoBase = WIDGET_BASE(wProjectBase, /COLUMN, SPACE=1, $
  6035.                                XPAD=1, YPAD=1, /FRAME)
  6036.    wProjResoLab = WIDGET_LABEL(wProjResoBase, VALUE='Resolution', $
  6037.                      /ALIGN_LEFT)
  6038.    wProjResoBase1 = WIDGET_BASE(wProjResoBase, /ROW, /EXCLUSIVE, $
  6039.                                 SPACE=1, XPAD=1, YPAD=1)
  6040.    wProjLowBttn = WIDGET_BUTTON(wProjResoBase1, VALUE='Low', $
  6041.                                 UVALUE='wProjLowBttn', /NO_RELEASE)
  6042.    wProjMedBttn = WIDGET_BUTTON(wProjResoBase1, VALUE='Med', $
  6043.                                 UVALUE='wProjMedBttn', /NO_RELEASE)
  6044.    wProjHighBttn = WIDGET_BUTTON(wProjResoBase1, VALUE='High', $
  6045.                                  UVALUE='wProjHighBttn', /NO_RELEASE)
  6046.    WIDGET_CONTROL, wProjMedBttn, /SET_BUTTON
  6047.    wProjDQSlid = WIDGET_SLIDER(wProjectBase, MIN=0, MAX=100, VALUE=100, $
  6048.                              UVALUE='wProjDQSlid', TITLE='Depth Queue %')
  6049.    wProjGoBttn = WIDGET_BUTTON(wProjectBase, VALUE='Display', $
  6050.                                UVALUE='wProjGoBttn')
  6051.  
  6052.  
  6053.    ; Profile base widgets.
  6054.    profWinY = 256
  6055.    wProfDraw = WIDGET_DRAW(wProfileBase, XSIZE=192, YSIZE=profWinY, $
  6056.       RETAIN=2, UVALUE='wProfDraw', /BUTTON_EVENTS)
  6057.    wProfTypeBase = WIDGET_BASE(wProfileBase, /COLUMN, /EXCLUSIVE, $
  6058.                                XPAD=1, YPAD=1, SPACE=1, /FRAME)
  6059.    wProfOrthoBttn = WIDGET_BUTTON(wProfTypeBase, Value='Orthogonal', $
  6060.       UVALUE='wProfOrthoBttn', /ALIGN_LEFT)
  6061.    wProfObliqBttn = WIDGET_BUTTON(wProfTypeBase, Value='Oblique', $
  6062.       UVALUE='wProfObliqBttn', /ALIGN_LEFT)
  6063.    WIDGET_CONTROL, wProfOrthoBttn, /SET_BUTTON
  6064.  
  6065.  
  6066.    ; Probe base widgets.
  6067.    wProbeXBase = WIDGET_BASE(wProbeBase, /ROW, XPAD=1, YPAD=1, SPACE=1)
  6068.    wProbeXLab = WIDGET_LABEL(wProbeXBase, VALUE='X')
  6069.    wProbeXText = WIDGET_TEXT(wProbeXBase, UVALUE='wProbeText', /EDITABLE, $
  6070.       VALUE=STRTRIM(STRING(FLOAT(szData(1)-1)/2.0)), XSIZE=12)
  6071.    wProbeYBase = WIDGET_BASE(wProbeBase, /ROW, XPAD=1, YPAD=1, SPACE=1)
  6072.    wProbeYLab = WIDGET_LABEL(wProbeYBase, VALUE='Y')
  6073.    wProbeYText = WIDGET_TEXT(wProbeYBase, UVALUE='wProbeText', /EDITABLE, $
  6074.       VALUE=STRTRIM(STRING(FLOAT(szData(2)-1)/2.0)), XSIZE=12)
  6075.    wProbeZBase = WIDGET_BASE(wProbeBase, /ROW, XPAD=1, YPAD=1, SPACE=1)
  6076.    wProbeZLab = WIDGET_LABEL(wProbeZBase, VALUE='Z')
  6077.    wProbeZText = WIDGET_TEXT(wProbeZBase, UVALUE='wProbeText', /EDITABLE, $
  6078.       VALUE=STRTRIM(STRING(FLOAT(szData(3)-1)/2.0)), XSIZE=12)
  6079.  
  6080.  
  6081.    ; View base widgets.
  6082.    ang1 = ( 30)
  6083.    ang2 = (-60)
  6084.    ang3 = (  0)
  6085.    wViewDrawBase = WIDGET_BASE(wViewBase, /ROW, SPACE=1, XPAD=1, YPAD=1)
  6086.    wViewDraw = WIDGET_DRAW(wViewDrawBase, XSIZE=128, YSIZE=128, $
  6087.       RETAIN=2, UVALUE='wViewDraw', /BUTTON_EVENTS)
  6088.    wViewDispBttn = WIDGET_BUTTON(wViewDrawBase, VALUE='Display', $
  6089.                       UVALUE='wViewDispBttn', /ALIGN_BOTTOM)
  6090.  
  6091.    wRotBase = WIDGET_BASE(wViewBase, /COLUMN, /FRAME, $
  6092.                  SPACE=1, XPAD=1, YPAD=1)
  6093.    wRotLab = WIDGET_LABEL(wRotBase, VALUE='Rotations:')
  6094.  
  6095.    wRot1Base = WIDGET_BASE(wRotBase, /ROW, SPACE=1, XPAD=1, YPAD=1)
  6096.    wRot1Slid = WIDGET_SLIDER(wRot1Base, Min=(-180), Max=(180), $
  6097.       VALUE=ang1, UVALUE='wRot1Slid', XSIZE=136, /DRAG)
  6098.    wRot1Drop = WIDGET_DROPLIST(wRot1Base, VALUE=['X','Y','Z'], $
  6099.                   UVALUE='wRot1Drop')
  6100.    WIDGET_CONTROL, wRot1Drop, SET_DROPLIST_SELECT=2
  6101.  
  6102.    wRot2Base = WIDGET_BASE(wRotBase, /ROW, SPACE=1, XPAD=1, YPAD=1)
  6103.    wRot2Slid = WIDGET_SLIDER(wRot2Base, Min=(-180), Max=(180), $
  6104.       VALUE=ang2, UVALUE='wRot2Slid', XSIZE=136, /DRAG)
  6105.    wRot2Drop = WIDGET_DROPLIST(wRot2Base, VALUE=['X','Y','Z'], $
  6106.                   UVALUE='wRot2Drop')
  6107.    WIDGET_CONTROL, wRot2Drop, SET_DROPLIST_SELECT=0
  6108.  
  6109. ;   wRot3Base = WIDGET_BASE(wRotBase, /ROW, SPACE=1, XPAD=1, YPAD=1)
  6110. ;   wid = WIDGET_LABEL(wRot3Base, VALUE='3')
  6111. ;   wRot3Slid = WIDGET_SLIDER(wRot3Base, Min=(-180), Max=(180), $
  6112. ;      VALUE=ang3, UVALUE='wRot3Slid', XSIZE=136, /DRAG)
  6113. ;   wRot3Drop = WIDGET_DROPLIST(wRot3Base, VALUE=['X','Y','Z'], $
  6114. ;                  UVALUE='wRot3Drop')
  6115. ;   WIDGET_CONTROL, wRot3Drop, SET_DROPLIST_SELECT=0
  6116.  
  6117.    wZoomBase = WIDGET_BASE(wViewBase, /ROW, SPACE=1, XPAD=1, YPAD=1, $
  6118.                            /FRAME)
  6119.    wZoomSlid = WIDGET_SLIDER(wZoomBase, Min=50, Max=100, VALUE=50, $
  6120.                   XSIZE=136, UVALUE='wZoomSlid', /DRAG)
  6121.    wid = WIDGET_LABEL(wZoomBase, VALUE='Zoom %')
  6122.  
  6123.    wZFacBase = WIDGET_BASE(wViewBase, /ROW, SPACE=1, XPAD=1, YPAD=1, $
  6124.                            /FRAME)
  6125.    wZFacSlid = WIDGET_SLIDER(wZFacBase, Min=50, Max=200, VALUE=100, $
  6126.                   XSIZE=136, UVALUE='wZFacSlid', /DRAG)
  6127.    wid = WIDGET_LABEL(wZfacBase, VALUE='Z %')
  6128.  
  6129. ;   wPerspBase = WIDGET_BASE(wViewBase, /ROW, SPACE=1, XPAD=1, YPAD=1, $
  6130. ;                            /FRAME)
  6131. ;   wPerspSlid = WIDGET_SLIDER(wPerspBase, Min=0, Max=10, VALUE=0, $
  6132. ;                   XSIZE=136, UVALUE='wPerspSlid', /DRAG)
  6133. ;   wid = WIDGET_LABEL(wPerspBase, VALUE='Persp.')
  6134.  
  6135.  
  6136.    ; Threshold base widgets.
  6137.    wThreshLabel = WIDGET_LABEL(wThreshBase, VALUE='Data Threshold', $
  6138.                                /ALIGN_LEFT)
  6139.    wThreshDraw = WIDGET_DRAW(wThreshBase, XSIZE=192, YSIZE=128, $
  6140.       RETAIN=2, UVALUE='wThreshDraw', /BUTTON_EVENTS)
  6141.    wThreshLowBase = WIDGET_BASE(wThreshBase, /ROW, SPACE=1, $
  6142.                                 XPAD=1, YPAD=1)
  6143.    wThreshLowText = WIDGET_TEXT(wThreshLowBase, XSIZE=8, YSIZE=1, /FRAME, $
  6144.                                 UVALUE='wThreshLowText', /EDITABLE)
  6145.    wThreshLowLabel = WIDGET_LABEL(wThreshLowBase, VALUE='Min')
  6146.    wThreshHighBase = WIDGET_BASE(wThreshBase, /ROW, SPACE=1, $
  6147.                                  XPAD=1, YPAD=1)
  6148.    wThreshHighText = WIDGET_TEXT(wThreshHighBase, XSIZE=8, YSIZE=1, /FRAME, $
  6149.                                 UVALUE='wThreshHighText', /EDITABLE)
  6150.    wThreshHighLabel = WIDGET_LABEL(wThreshHighBase, VALUE='Max')
  6151.    wThreshTransBase = WIDGET_BASE(wThreshBase, /ROW, SPACE=1, $
  6152.                                   XPAD=1, YPAD=1)
  6153.    wThreshTransText = WIDGET_TEXT(wThreshTransBase, XSIZE=8, YSIZE=1, $
  6154.                          /FRAME, UVALUE='wThreshTransText', /EDITABLE)
  6155.    wThreshTransLabel = WIDGET_LABEL(wThreshTransBase, VALUE='Transp.')
  6156.  
  6157.    ; Set the color mode.
  6158.    if (!D.N_Colors GT 256L) then DEVICE, DECOMPOSED=0
  6159.  
  6160.    ; Create the pixmap used for profiling.
  6161.    WINDOW, /FREE, /PIXMAP, XSIZE=192, YSIZE=profWinY, RETAIN=2
  6162.    profPix = !D.Window
  6163.  
  6164.    ; Create the pixmap used for the surface histogram.
  6165.    WINDOW, /FREE, /PIXMAP, XSIZE=192, YSIZE=128, RETAIN=2
  6166.    surfPix = !D.Window
  6167.  
  6168.    ; Create the pixmap used for the threshold histogram.
  6169.    WINDOW, /FREE, /PIXMAP, XSIZE=192, YSIZE=128, RETAIN=2
  6170.    threshPix = !D.Window
  6171.  
  6172.    ; Create the pixmap used for dynamic screen updating.
  6173.    WINDOW, /FREE, /PIXMAP, XSIZE=winX, YSIZE=winY, RETAIN=2
  6174.    XYOUTS, 0, 0, '.', /DEVICE
  6175.    ERASE
  6176.    pixWin = !D.Window
  6177.  
  6178.    ; Initialize the Z buffer.
  6179.    screenDevice = !D.Name
  6180.    SET_PLOT, 'Z'
  6181.    DEVICE, /Z_BUFFERING, SET_RESOLUTION=[winX, winY]
  6182.    SET_PLOT, screenDevice
  6183.  
  6184.    if ((detachBase) and NOT(KEYWORD_SET(runModal))) then $
  6185.       WIDGET_CONTROL, wDrawBase, /REALIZE
  6186.    WIDGET_CONTROL, wMainBase, /REALIZE
  6187.  
  6188.    WIDGET_CONTROL, /HOURGLASS
  6189.  
  6190.    WIDGET_CONTROL, wMainDraw, GET_VALUE=mainWin
  6191.    WIDGET_CONTROL, wSliceDraw, GET_VALUE=sliceWin
  6192.    WIDGET_CONTROL, wBlockDraw, GET_VALUE=blockWin
  6193.    WIDGET_CONTROL, wSurfDraw, GET_VALUE=SurfWin
  6194.    WIDGET_CONTROL, wThreshDraw, GET_VALUE=threshWin
  6195.    WIDGET_CONTROL, wProfDraw, GET_VALUE=profWin
  6196.    WIDGET_CONTROL, wViewDraw, GET_VALUE=viewWin
  6197.    WSET, mainWin
  6198.  
  6199.    ; Set up the color state.
  6200.    sColorState = Viz3D_LoadColor(DIFFSHADE=20)
  6201.  
  6202.    ; View state.
  6203.    sViewState = Viz3D_View(viewWin, ANG1=ang1, ANG2=ang2, ANG3=ang3, $
  6204.       DIR1='Z', DIR2='X', DIR3='Y', ZOOM=0.75, XMAX=szData(1)-1L, $
  6205.       YMAX=szData(2)-1L, ZMAX=szData(3)-1L)
  6206.    WIDGET_CONTROL, wZoomSlid, SET_VALUE=ROUND(100.0 * sViewState.zoomFac)
  6207.  
  6208.    ; Threshold state.
  6209.    hMinData = HANDLE_CREATE(hMain, VALUE=minData)
  6210.    hMaxData = HANDLE_CREATE(hMain, VALUE=maxData)
  6211.    hLowThresh = HANDLE_CREATE(hMain, VALUE=minData)
  6212.    hHighThresh = HANDLE_CREATE(hMain, VALUE=maxData)
  6213.    hTransVal = HANDLE_CREATE(hMain, VALUE=minData)
  6214.    sThreshState = {SThreshState, $
  6215.                    histColor:7, lowColor:2, highColor:5, $
  6216.                    axisColor:3, transColor:6, $
  6217.                    wThreshDraw:wThreshDraw, $
  6218.                    wThreshLowText:wThreshLowText, $
  6219.                    wThreshHighText:wThreshHighText, $
  6220.                    wThreshTransText:wThreshTransText, $
  6221.                    threshWin:threshWin, hDataHist:hDataHist, $
  6222.                    threshPix:threshPix, $
  6223.                    hMinData:hMinData, hMaxData:hMaxData, $
  6224.                    hTransVal:hTransVal, $
  6225.                    hLowThresh:hLowThresh, $
  6226.                    hHighThresh:hHighThresh, $
  6227.                    moveType:0}
  6228.    WIDGET_CONTROL, wThreshLowText, $
  6229.       SET_VALUE=STRTRIM(STRING(minData(0)),2)
  6230.    WIDGET_CONTROL, wThreshHighText, $
  6231.       SET_VALUE=STRTRIM(STRING(maxData(0)),2)
  6232.  
  6233.    ; Slice state.
  6234.    sSliceState = $
  6235.       {SSliceState, sliceWin:sliceWin, $
  6236.        wSliceOrthoBase:wSliceOrthoBase, wSliceObliqBase:wSliceObliqBase, $
  6237.        wSliceXBttn:wSliceXBttn, wSliceYBttn:wSliceYBttn, $
  6238.        wSliceZBttn:wSliceZBttn, drawMode:0, planeMode:1, orthoDir:1, $
  6239.        orthoPos:0.5, obliqNormal:[0.0,0.0,1.0], obliqCenter:[0.5,0.5,0.5], $
  6240.        obliqMove:0, edgeColor:6, fillColor:1, normColor:5}
  6241.  
  6242.    ; Block state.
  6243.    sBlockState = $
  6244.       {SBlockState, blockWin:blockWin, $
  6245.        blockMode:1, c1:[szData(1)-1, szData(2)-1, szData(3)-1]/3, $
  6246.        c2:(2*[szData(1)-1, szData(2)-1, szData(3)-1])/3, $
  6247.        blockColor:6, c1Color:4, c2Color:1, frontBack:1}
  6248.  
  6249.    ; Iso-surface state.
  6250.    hSurfThresh = HANDLE_CREATE(hMain, $
  6251.       VALUE=(TEMPORARY(minData) + TEMPORARY(maxData))/2.0D)
  6252.    sSurfState = $
  6253.       {SSurfState, surfWin:surfWin, wSurfShadeBase:wSurfShadeBase, $
  6254.        surfPix:surfPix, wSurfShadeDrop:wSurfShadeDrop, curShade:0, $
  6255.        histColor:7, tColor:2, axisColor:3, hRangeHist:hRangeHist, $
  6256.        surfSide:0, hSurfThresh:hSurfThresh, wSurfText:wSurfText}
  6257.  
  6258.    ; Projection state.
  6259.    sProjState = $
  6260.       {SProjState, projType:0, projReso:1, depthQ:100}
  6261.  
  6262.    ; Profile state.
  6263.    sProfState = $
  6264.       {SProfState, profType:0, profDir:1, frontBack:1, onFace:1, $
  6265.        x1Ortho:FLOAT(szData(1)-1)/2.0, x2Ortho:FLOAT(szData(1)-1)/2.0, $
  6266.        y1Ortho:FLOAT(szData(2)-1)/2.0, y2Ortho:FLOAT(szData(2)-1)/2.0, $
  6267.        z1Ortho:0.0, z2Ortho:FLOAT(szData(3)-1), $
  6268.        x1Obliq:FLOAT(szData(1)-1)/2.0, x2Obliq:FLOAT(szData(1)-1)/2.0, $
  6269.        y1Obliq:FLOAT(szData(2)-1)/2.0, y2Obliq:FLOAT(szData(2)-1)/2.0, $
  6270.        z1Obliq:0.0, z2Obliq:FLOAT(szData(3)-1), $
  6271.        lineColor:6, axisColor:3, markColor1:4, markColor2:1, $
  6272.        profWin:profWin, profPix:profPix, profWinY:profWinY}
  6273.  
  6274.    ; Profile state.
  6275.    sProbeState = $
  6276.       {SProbeState, wProbeXText:wProbeXText, wProbeYText:wProbeYText, $
  6277.                     wProbeZText:wProbeZText, x:FLOAT(szData(1)-1)/2.0, $
  6278.                     y:FLOAT(szData(2)-1)/2.0, z:FLOAT(szData(3)-1)/2.0, $
  6279.                     lineColor:1}
  6280.  
  6281.    ; Main state.
  6282.    sMainState = {SVizState, curData:0, $
  6283.        szData:szData, detachBase:detachBase, winX:winX, winY:winY, $
  6284.        actMode:0, wMainBase:wMainBase, wDrawBase:wDrawBase, $
  6285.        wMainDraw:wMainDraw, wSliceBase:wSliceBase, wBlockBase:wBlockBase, $
  6286.        wSurfBase:wSurfBase, wThreshBase:wThreshBase, $
  6287.        wProjectBase:wProjectBase, wProfileBase:wProfileBase, $
  6288.        wProbeBase:wProbeBase, wViewBase:wViewBase, wCurMapBase:wSliceBase, $
  6289.        wStatText:wStatText, wSaveSubsetBttn:wSaveSubsetBttn, $
  6290.        wDeleteMenu:wDeleteMenu, wDataModeBase:wDataModeBase, $
  6291.        wDataDrop:wDataDrop, mainWin:mainWin, pixWin:pixWin, interpMode:1, $
  6292.        hMain:hMain, hDisplayList:hDisplayList, hDataList:hDataList, $
  6293.        hDataName:hDataName, cubeOn:1, axisOn:1, $
  6294.        cubeColor:3, axisColor:2, backColor:0, screenDevice:screenDevice, $
  6295.        cleanupView:0, cleanupBuffer:0, $
  6296.        hFrontDepth:HANDLE_CREATE(hMain, VALUE=Intarr(winX,winY)), $
  6297.        hBackDepth:HANDLE_CREATE(hMain, VALUE=Intarr(winX,winY)), $
  6298.        hFrontImage:HANDLE_CREATE(hMain, VALUE=Bytarr(winX,winY)), $
  6299.        hBackImage:HANDLE_CREATE(hMain, VALUE=Bytarr(winX,winY)), $
  6300.        sColorState:Temporary(sColorState), $
  6301.        sSliceState:Temporary(sSliceState), $
  6302.        sBlockState:Temporary(sBlockState), $
  6303.        sSurfState:Temporary(sSurfState), $
  6304.        sProjState:Temporary(sProjState), $
  6305.        sViewState:Temporary(sViewState), $
  6306.        sProfState:Temporary(sProfState), $
  6307.        sProbeState:Temporary(sProbeState), $
  6308.        sThreshState:Temporary(sThreshState)}
  6309.  
  6310.    ; Fill the depth and image buffers.
  6311.    Viz3D_FillDepth, sMainState
  6312.  
  6313.    ; Draw the contents of the small windows.
  6314.    Viz3D_SliceShow, sMainState
  6315.    Viz3D_SurfShow, sMainState, /CALC_HIST
  6316.    Viz3D_ThreshShow, sMainState
  6317.    Viz3D_ViewShow, sMainState
  6318.  
  6319.    ; Draw cube in main window.
  6320.    SET_PLOT, 'Z'
  6321.    ERASE
  6322.    SET_PLOT, screenDevice
  6323.    Viz3D_DrawData, sMainState
  6324.  
  6325.    ; Put the main state in the top level base.
  6326.    WIDGET_CONTROL, wMainBase, SET_UVALUE=sMainState, /NO_COPY
  6327.  
  6328.    ; Turn off the hourglass cursor.
  6329.    event = WIDGET_EVENT(wMainBase, /NOWAIT)
  6330.  
  6331.    if (KEYWORD_SET(runModal)) then begin
  6332.  
  6333.       ; Start event processing.
  6334.  
  6335.       XMANAGER, 'Slicer3', wMainBase, EVENT_HANDLER='Viz3D_Event', $
  6336.          /MODAL
  6337.  
  6338.       ; All done, cleanup.
  6339.  
  6340.       HANDLE_FREE, hMain
  6341.       WDELETE, pixWin
  6342.       WDELETE, profPix
  6343.       WDELETE, surfPix
  6344.       WDELETE, threshPix
  6345.  
  6346.       ; Restore the system variables to their previous state.
  6347.       !Order = saveOrder
  6348.       !P = TEMPORARY(saveP)
  6349.       !X = TEMPORARY(saveX)
  6350.       !Y = TEMPORARY(saveY)
  6351.       !Z = TEMPORARY(saveZ)
  6352.  
  6353.       ; Restore the previous color table.
  6354.       r = TEMPORARY(saveR)
  6355.       g = TEMPORARY(saveG)
  6356.       b = TEMPORARY(saveB)
  6357.       cur_red = TEMPORARY(save_curR)
  6358.       cur_green = TEMPORARY(save_curG)
  6359.       cur_blue = TEMPORARY(save_curB)
  6360.  
  6361.       ; Make the previous IDL window active.
  6362.       if (saveWin ge 0L) then WSET, saveWin
  6363.  
  6364.    endif else begin
  6365.  
  6366.       ; Start event processing.
  6367.       if (detachBase) then $
  6368.          XMANAGER, 'Slicer3', wDrawBase, /JUST_REG, $
  6369.             EVENT_HANDLER='Viz3D_SliceEvent', CLEANUP='Viz3D_KillDraw'
  6370.  
  6371.       XMANAGER, 'Slicer3', wMainBase, EVENT_HANDLER='Viz3D_Event', $
  6372.          CLEANUP='Viz3D_KillMain'
  6373.  
  6374.    endelse
  6375.  
  6376. end
  6377. ;******************************************************************************
  6378.  
  6379.